d: Import dmd b8384668f, druntime e6caaab9, phobos 5ab9ad256 (v2.098.0-beta.1)
The D front-end is now itself written in D, in order to build GDC, you will need a working GDC compiler (GCC version 9.1 or later). GCC changes: - Add support for bootstrapping the D front-end. These add the required components in order to have a D front-end written in D itself. Because the compiler front-end only depends on the core runtime modules, only libdruntime is built for the bootstrap stages. D front-end changes: - Import dmd v2.098.0-beta.1. Druntime changes: - Import druntime v2.098.0-beta.1. Phobos changes: - Import phobos v2.098.0-beta.1. The jump from v2.076.1 to v2.098.0 covers nearly 4 years worth of development on the D programming language and run-time libraries. ChangeLog: * Makefile.def: Add bootstrap to libbacktrace, libphobos, zlib, and libatomic. * Makefile.in: Regenerate. * Makefile.tpl (POSTSTAGE1_HOST_EXPORTS): Fix command for GDC. (STAGE1_CONFIGURE_FLAGS): Add --with-libphobos-druntime-only if target-libphobos-bootstrap. (STAGE2_CONFIGURE_FLAGS): Likewise. * configure: Regenerate. * configure.ac: Add support for bootstrapping D front-end. config/ChangeLog: * acx.m4 (ACX_PROG_GDC): New m4 function. gcc/ChangeLog: * Makefile.in (GDC): New variable. (GDCFLAGS): New variable. * configure: Regenerate. * configure.ac: Add call to ACX_PROG_GDC. Substitute GDCFLAGS. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd b8384668f. * Make-lang.in (d-warn): Use strict warnings. (DMD_WARN_CXXFLAGS): Remove. (DMD_COMPILE): Remove. (CHECKING_DFLAGS): Define. (WARN_DFLAGS): Define. (ALL_DFLAGS): Define. (DCOMPILE.base): Define. (DCOMPILE): Define. (DPOSTCOMPILE): Define. (DLINKER): Define. (DLLINKER): Define. (D_FRONTEND_OBJS): Add new dmd front-end objects. (D_GENERATED_SRCS): Remove. (D_GENERATED_OBJS): Remove. (D_ALL_OBJS): Remove D_GENERATED_OBJS. (d21$(exeext)): Build using DLLINKER and -static-libphobos. (d.tags): Remove dmd/*.c and dmd/root/*.c. (d.mostlyclean): Remove D_GENERATED_SRCS, d/idgen$(build_exeext), d/impcnvgen$(build_exeext). (D_INCLUDES): Include $(srcdir)/d/dmd/res. (CFLAGS-d/id.o): Remove. (CFLAGS-d/impcnvtab.o): Remove. (d/%.o): Build using DCOMPILE and DPOSTCOMPILE. Update dependencies from d/dmd/%.c to d/dmd/%.d. (d/idgen$(build_exeext)): Remove. (d/impcnvgen$(build_exeext)): Remove. (d/id.c): Remove. (d/id.h): Remove. (d/impcnvtab.c): Remove. (d/%.dmdgen.o): Remove. (D_SYSTEM_H): Remove. (d/idgen.dmdgen.o): Remove. (d/impcnvgen.dmdgen.o): Remove. * config-lang.in (boot_language): New variable. * d-attribs.cc: Include dmd/expression.h. * d-builtins.cc: Include d-frontend.h. (build_frontend_type): Update for new front-end interface. (d_eval_constant_expression): Likewise. (d_build_builtins_module): Likewise. (maybe_set_builtin_1): Likewise. (d_build_d_type_nodes): Likewise. * d-codegen.cc (d_decl_context): Likewise. (declaration_reference_p): Likewise. (declaration_type): Likewise. (parameter_reference_p): Likewise. (parameter_type): Likewise. (get_array_length): Likewise. (build_delegate_cst): Likewise. (build_typeof_null_value): Likewise. (identity_compare_p): Likewise. (lower_struct_comparison): Likewise. (build_filename_from_loc): Likewise. (build_assert_call): Remove LIBCALL_SWITCH_ERROR. (build_bounds_index_condition): Call LIBCALL_ARRAYBOUNDS_INDEXP on bounds error. (build_bounds_slice_condition): Call LIBCALL_ARRAYBOUNDS_SLICEP on bounds error. (array_bounds_check): Update for new front-end interface. (checkaction_trap_p): Handle CHECKACTION_context. (get_function_type): Update for new front-end interface. (d_build_call): Likewise. * d-compiler.cc: Remove include of dmd/scope.h. (Compiler::genCmain): Remove. (Compiler::paintAsType): Update for new front-end interface. (Compiler::onParseModule): Likewise. * d-convert.cc (convert_expr): Remove call to LIBCALL_ARRAYCAST. (convert_for_rvalue): Update for new front-end interface. (convert_for_assignment): Likewise. (convert_for_condition): Likewise. (d_array_convert): Likewise. * d-diagnostic.cc (error): Remove. (errorSupplemental): Remove. (warning): Remove. (warningSupplemental): Remove. (deprecation): Remove. (deprecationSupplemental): Remove. (message): Remove. (vtip): New. * d-frontend.cc (global): Remove. (Global::_init): Remove. (Global::startGagging): Remove. (Global::endGagging): Remove. (Global::increaseErrorCount): Remove. (Loc::Loc): Remove. (Loc::toChars): Remove. (Loc::equals): Remove. (isBuiltin): Update for new front-end interface. (eval_builtin): Likewise. (getTypeInfoType): Likewise. (inlineCopy): Remove. * d-incpath.cc: Include d-frontend.h. (add_globalpaths): Call d_gc_malloc to allocate Strings. (add_filepaths): Likewise. * d-lang.cc: Include dmd/id.h, dmd/root/file.h, d-frontend.h. Remove include of dmd/mars.h, id.h. (entrypoint_module): Remove. (entrypoint_root_module): Remove. (deps_write_string): Update for new front-end interface. (deps_write): Likewise. (d_init_options): Call rt_init. Remove setting global params that are default initialized by the front-end. (d_handle_option): Handle OPT_fcheckaction_, OPT_fdump_c___spec_, OPT_fdump_c___spec_verbose, OPT_fextern_std_, OPT_fpreview, OPT_revert, OPT_fsave_mixins_, and OPT_ftransition. (d_post_options): Propagate dip1021 and dip1000 preview flags to dip25, and flag_diagnostics_show_caret to printErrorContext. (d_add_entrypoint_module): Remove. (d_parse_file): Update for new front-end interface. (d_type_promotes_to): Likewise. (d_types_compatible_p): Likewise. * d-longdouble.cc (CTFloat::zero): Remove. (CTFloat::one): Remove. (CTFloat::minusone): Remove. (CTFloat::half): Remove. * d-system.h (POSIX): Remove. (realpath): Remove. (isalpha): Remove. (isalnum): Remove. (isdigit): Remove. (islower): Remove. (isprint): Remove. (isspace): Remove. (isupper): Remove. (isxdigit): Remove. (tolower): Remove. (_mkdir): Remove. (INT32_MAX): Remove. (INT32_MIN): Remove. (INT64_MIN): Remove. (UINT32_MAX): Remove. (UINT64_MAX): Remove. * d-target.cc: Include calls.h. (target): Remove. (define_float_constants): Remove initialization of snan. (Target::_init): Update for new front-end interface. (Target::isVectorTypeSupported): Likewise. (Target::isVectorOpSupported): Remove cases for unordered operators. (TargetCPP::typeMangle): Update for new front-end interface. (TargetCPP::parameterType): Likewise. (Target::systemLinkage): Likewise. (Target::isReturnOnStack): Likewise. (Target::isCalleeDestroyingArgs): Define. (Target::preferPassByRef): Define. * d-tree.h (d_add_entrypoint_module): Remove. * decl.cc (gcc_attribute_p): Update for new front-end interface. (apply_pragma_crt): Define. (DeclVisitor::visit(PragmaDeclaration *)): Handle pragmas crt_constructor and crt_destructor. (DeclVisitor::visit(TemplateDeclaration *)): Update for new front-end interface. (DeclVisitor::visit): Likewise. (DeclVisitor::finish_vtable): Likewise. (get_symbol_decl): Error if template has more than one nesting context. Update for new front-end interface. (make_thunk): Update for new front-end interface. (get_vtable_decl): Likewise. * expr.cc (ExprVisitor::visit): Likewise. (build_return_dtor): Likewise. * imports.cc (ImportVisitor::visit): Likewise. * intrinsics.cc: Include dmd/expression.h. Remove include of dmd/mangle.h. (maybe_set_intrinsic): Update for new front-end interface. * intrinsics.def (INTRINSIC_ROL): Update intrinsic signature. (INTRINSIC_ROR): Likewise. (INTRINSIC_ROR_TIARG): Likewise. (INTRINSIC_TOPREC): Likewise. (INTRINSIC_TOPRECL): Likewise. (INTRINSIC_TAN): Update intrinsic module and signature. (INTRINSIC_ISNAN): Likewise. (INTRINSIC_ISFINITE): Likewise. (INTRINSIC_COPYSIGN): Define intrinsic. (INTRINSIC_COPYSIGNI): Define intrinsic. (INTRINSIC_EXP): Update intrinsic module. (INTRINSIC_EXPM1): Likewise. (INTRINSIC_EXP2): Likewise. (INTRINSIC_LOG): Likewise. (INTRINSIC_LOG2): Likewise. (INTRINSIC_LOG10): Likewise. (INTRINSIC_POW): Likewise. (INTRINSIC_ROUND): Likewise. (INTRINSIC_FLOORF): Likewise. (INTRINSIC_FLOOR): Likewise. (INTRINSIC_FLOORL): Likewise. (INTRINSIC_CEILF): Likewise. (INTRINSIC_CEIL): Likewise. (INTRINSIC_CEILL): Likewise. (INTRINSIC_TRUNC): Likewise. (INTRINSIC_FMIN): Likewise. (INTRINSIC_FMAX): Likewise. (INTRINSIC_FMA): Likewise. (INTRINSIC_VA_ARG): Update intrinsic signature. (INTRINSIC_VASTART): Likewise. * lang.opt (fcheck=): Add alternate aliases for contract switches. (fcheckaction=): New option. (check_action): New Enum and EnumValue entries. (fdump-c++-spec-verbose): New option. (fdump-c++-spec=): New option. (fextern-std=): New option. (extern_stdcpp): New Enum and EnumValue entries (fpreview=): New options. (frevert=): New options. (fsave-mixins): New option. (ftransition=): Update options. * modules.cc (get_internal_fn): Replace Prot with Visibility. (build_internal_fn): Likewise. (build_dso_cdtor_fn): Likewise. (build_module_tree): Remove check for __entrypoint module. * runtime.def (P5): Define. (ARRAYBOUNDS_SLICEP): Define. (ARRAYBOUNDS_INDEXP): Define. (NEWTHROW): Define. (ADCMP2): Remove. (ARRAYCAST): Remove. (SWITCH_STRING): Remove. (SWITCH_USTRING): Remove. (SWITCH_DSTRING): Remove. (SWITCH_ERROR): Remove. * toir.cc (IRVisitor::visit): Update for new front-end interface. (IRVisitor::check_previous_goto): Remove checks for case and default statements. (IRVisitor::visit(SwitchStatement *)): Remove handling of string switch conditions. * typeinfo.cc: Include d-frontend.h. (get_typeinfo_kind): Update for new front-end interface. (make_frontend_typeinfo): Likewise. (TypeInfoVisitor::visit): Likewise. (builtin_typeinfo_p): Likewise. (get_typeinfo_decl): Likewise. (build_typeinfo): Likewise. * types.cc (valist_array_p): Likewise. (make_array_type): Likewise. (merge_aggregate_types): Likewise. (TypeVisitor::visit(TypeBasic *)): Likewise. (TypeVisitor::visit(TypeFunction *)): Likewise. (TypeVisitor::visit(TypeStruct *)): Update comment. * verstr.h: Removed. * d-frontend.h: New file. gcc/po/ChangeLog: * EXCLUDES: Remove d/dmd sources from list. gcc/testsuite/ChangeLog: * gdc.dg/Wcastresult2.d: Update test. * gdc.dg/asm1.d: Likewise. * gdc.dg/asm2.d: Likewise. * gdc.dg/asm3.d: Likewise. * gdc.dg/gdc282.d: Likewise. * gdc.dg/imports/gdc170.d: Likewise. * gdc.dg/intrinsics.d: Likewise. * gdc.dg/pr101672.d: Likewise. * gdc.dg/pr90650a.d: Likewise. * gdc.dg/pr90650b.d: Likewise. * gdc.dg/pr94777a.d: Likewise. * gdc.dg/pr95250.d: Likewise. * gdc.dg/pr96869.d: Likewise. * gdc.dg/pr98277.d: Likewise. * gdc.dg/pr98457.d: Likewise. * gdc.dg/simd1.d: Likewise. * gdc.dg/simd2a.d: Likewise. * gdc.dg/simd2b.d: Likewise. * gdc.dg/simd2c.d: Likewise. * gdc.dg/simd2d.d: Likewise. * gdc.dg/simd2e.d: Likewise. * gdc.dg/simd2f.d: Likewise. * gdc.dg/simd2g.d: Likewise. * gdc.dg/simd2h.d: Likewise. * gdc.dg/simd2i.d: Likewise. * gdc.dg/simd2j.d: Likewise. * gdc.dg/simd7951.d: Likewise. * gdc.dg/torture/gdc309.d: Likewise. * gdc.dg/torture/pr94424.d: Likewise. * gdc.dg/torture/pr94777b.d: Likewise. * lib/gdc-utils.exp (gdc-convert-args): Handle new compiler options. (gdc-convert-test): Handle CXXFLAGS, EXTRA_OBJC_SOURCES, and ARG_SETS test directives. (gdc-do-test): Only import modules in the test run directory. * gdc.dg/pr94777c.d: New test. * gdc.dg/pr96156b.d: New test. * gdc.dg/pr96157c.d: New test. * gdc.dg/simd_ctfe.d: New test. * gdc.dg/torture/simd17344.d: New test. * gdc.dg/torture/simd20052.d: New test. * gdc.dg/torture/simd6.d: New test. * gdc.dg/torture/simd7.d: New test. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime e6caaab9. * libdruntime/Makefile.am (D_EXTRA_FLAGS): Build libdruntime with -fpreview=dip1000, -fpreview=fieldwise, and -fpreview=dtorfields. (ALL_DRUNTIME_SOURCES): Add DRUNTIME_DSOURCES_STDCXX. (DRUNTIME_DSOURCES): Update list of C binding modules. (DRUNTIME_DSOURCES_STDCXX): Likewise. (DRUNTIME_DSOURCES_LINUX): Likewise. (DRUNTIME_DSOURCES_OPENBSD): Likewise. (DRUNTIME_DISOURCES): Remove __entrypoint.di. * libdruntime/Makefile.in: Regenerated. * libdruntime/__entrypoint.di: Removed. * libdruntime/gcc/deh.d (_d_isbaseof): Update signature. (_d_createTrace): Likewise. (__gdc_begin_catch): Remove reference to the exception. (_d_throw): Increment reference count of thrown object before unwind. (__gdc_personality): Chain exceptions with Throwable.chainTogether. * libdruntime/gcc/emutls.d: Update imports. * libdruntime/gcc/sections/elf.d: Update imports. (DSO.moduleGroup): Update signature. * libdruntime/gcc/sections/macho.d: Update imports. (DSO.moduleGroup): Update signature. * libdruntime/gcc/sections/pecoff.d: Update imports. (DSO.moduleGroup): Update signature. * src/MERGE: Merge upstream phobos 5ab9ad256. * src/Makefile.am (D_EXTRA_DFLAGS): Add -fpreview=dip1000 and -fpreview=dtorfields flags. (PHOBOS_DSOURCES): Update list of std modules. * src/Makefile.in: Regenerate. * testsuite/lib/libphobos.exp (libphobos-dg-test): Handle assembly compile types. (dg-test): Override. (additional_prunes): Define. (libphobos-dg-prune): Filter any additional_prunes set by tests. * testsuite/libphobos.aa/test_aa.d: Update test. * testsuite/libphobos.druntime/druntime.exp (version_flags): Add -fversion=CoreUnittest. * testsuite/libphobos.druntime_shared/druntime_shared.exp (version_flags): Add -fversion=CoreUnittest -fversion=Shared. * testsuite/libphobos.exceptions/unknown_gc.d: Update test. * testsuite/libphobos.hash/test_hash.d: Update test. * testsuite/libphobos.phobos/phobos.exp (version_flags): Add -fversion=StdUnittest * testsuite/libphobos.phobos_shared/phobos_shared.exp (version_flags): Likewise. * testsuite/libphobos.shared/host.c: Update test. * testsuite/libphobos.shared/load.d: Update test. * testsuite/libphobos.shared/load_13414.d: Update test. * testsuite/libphobos.thread/fiber_guard_page.d: Update test. * testsuite/libphobos.thread/tlsgc_sections.d: Update test. * testsuite/testsuite_flags.in: Add -fpreview=dip1000 to --gdcflags. * testsuite/libphobos.shared/link_mod_collision.d: Removed. * testsuite/libphobos.shared/load_mod_collision.d: Removed. * testsuite/libphobos.betterc/betterc.exp: New test. * testsuite/libphobos.config/config.exp: New test. * testsuite/libphobos.gc/gc.exp: New test. * testsuite/libphobos.imports/imports.exp: New test. * testsuite/libphobos.lifetime/lifetime.exp: New test. * testsuite/libphobos.unittest/unittest.exp: New test.
This commit is contained in:
parent
b3f60112ed
commit
5fee5ec362
2803 changed files with 336333 additions and 191383 deletions
|
@ -169,14 +169,14 @@ target_modules = { module= newlib; };
|
|||
target_modules = { module= libgcc; bootstrap=true; no_check=true;
|
||||
missing=TAGS;
|
||||
missing=install-dvi; };
|
||||
target_modules = { module= libbacktrace; };
|
||||
target_modules = { module= libbacktrace; bootstrap=true; };
|
||||
target_modules = { module= libquadmath; };
|
||||
target_modules = { module= libgfortran; };
|
||||
target_modules = { module= libobjc;
|
||||
missing=TAGS;
|
||||
missing=install-dvi; };
|
||||
target_modules = { module= libgo; };
|
||||
target_modules = { module= libphobos;
|
||||
target_modules = { module= libphobos; bootstrap=true;
|
||||
lib_path=src/.libs; };
|
||||
target_modules = { module= libtermcap; no_check=true;
|
||||
missing=mostlyclean;
|
||||
|
@ -186,12 +186,12 @@ target_modules = { module= libtermcap; no_check=true;
|
|||
target_modules = { module= winsup; };
|
||||
target_modules = { module= libgloss; no_check=true; };
|
||||
target_modules = { module= libffi; no_install=true; };
|
||||
target_modules = { module= zlib; };
|
||||
target_modules = { module= zlib; bootstrap=true; };
|
||||
target_modules = { module= rda; };
|
||||
target_modules = { module= libada; };
|
||||
target_modules = { module= libgomp; bootstrap= true; lib_path=.libs; };
|
||||
target_modules = { module= libitm; lib_path=.libs; };
|
||||
target_modules = { module= libatomic; lib_path=.libs; };
|
||||
target_modules = { module= libatomic; bootstrap=true; lib_path=.libs; };
|
||||
|
||||
// These are (some of) the make targets to be done in each subdirectory.
|
||||
// Not all; these are the ones which don't have special options.
|
||||
|
|
3307
Makefile.in
3307
Makefile.in
File diff suppressed because it is too large
Load diff
12
Makefile.tpl
12
Makefile.tpl
|
@ -276,11 +276,14 @@ POSTSTAGE1_HOST_EXPORTS = \
|
|||
$(POSTSTAGE1_CXX_EXPORT) \
|
||||
$(LTO_EXPORTS) \
|
||||
GDC="$$r/$(HOST_SUBDIR)/prev-gcc/gdc$(exeext) -B$$r/$(HOST_SUBDIR)/prev-gcc/ \
|
||||
-B$(build_tooldir)/bin/ $(GDC_FLAGS_FOR_TARGET) \
|
||||
-B$(build_tooldir)/bin/ $(GDCFLAGS_FOR_TARGET) \
|
||||
-B$$r/prev-$(TARGET_SUBDIR)/libphobos/libdruntime/gcc \
|
||||
-B$$r/prev-$(TARGET_SUBDIR)/libphobos/src \
|
||||
-B$$r/prev-$(TARGET_SUBDIR)/libphobos/src/.libs \
|
||||
-I$$r/prev-$(TARGET_SUBDIR)/libphobos/libdruntime -I$$s/libphobos/libdruntime \
|
||||
-L$$r/prev-$(TARGET_SUBDIR)/libphobos/src/.libs \
|
||||
-L$$r/prev-$(TARGET_SUBDIR)/libphobos/libdruntime/.libs"; \
|
||||
-B$$r/prev-$(TARGET_SUBDIR)/libstdc++-v3/src/.libs \
|
||||
-L$$r/prev-$(TARGET_SUBDIR)/libstdc++-v3/src/.libs"; \
|
||||
export GDC; \
|
||||
GDC_FOR_BUILD="$$GDC"; export GDC_FOR_BUILD; \
|
||||
GNATBIND="$$r/$(HOST_SUBDIR)/prev-gcc/gnatbind"; export GNATBIND; \
|
||||
|
@ -487,6 +490,11 @@ STAGE1_CONFIGURE_FLAGS = --disable-intermodule $(STAGE1_CHECKING) \
|
|||
--disable-coverage --enable-languages="$(STAGE1_LANGUAGES)" \
|
||||
--disable-build-format-warnings
|
||||
|
||||
@if target-libphobos-bootstrap
|
||||
STAGE1_CONFIGURE_FLAGS += --with-libphobos-druntime-only
|
||||
STAGE2_CONFIGURE_FLAGS += --with-libphobos-druntime-only
|
||||
@endif target-libphobos-bootstrap
|
||||
|
||||
# When using the slow stage1 compiler disable IL verification and forcefully
|
||||
# enable it when using the stage2 compiler instead. As we later compare
|
||||
# stage2 and stage3 we are merely avoid doing redundant work, plus we apply
|
||||
|
|
|
@ -420,6 +420,18 @@ else
|
|||
fi
|
||||
])
|
||||
|
||||
# Test for D.
|
||||
AC_DEFUN([ACX_PROG_GDC],
|
||||
[AC_REQUIRE([AC_CHECK_TOOL_PREFIX])
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_CHECK_TOOL(GDC, gdc, no)
|
||||
if test "x$GDC" != xno; then
|
||||
have_gdc=yes
|
||||
else
|
||||
have_gdc=no
|
||||
fi
|
||||
])
|
||||
|
||||
dnl 'make compare' can be significantly faster, if cmp itself can
|
||||
dnl skip bytes instead of using tail. The test being performed is
|
||||
dnl "if cmp --ignore-initial=2 t1 t2 && ! cmp --ignore-initial=1 t1 t2"
|
||||
|
|
133
configure
vendored
133
configure
vendored
|
@ -619,6 +619,7 @@ GFORTRAN_FOR_TARGET
|
|||
GCC_FOR_TARGET
|
||||
CXX_FOR_TARGET
|
||||
CC_FOR_TARGET
|
||||
GDCFLAGS
|
||||
READELF
|
||||
OTOOL
|
||||
OBJDUMP
|
||||
|
@ -702,6 +703,7 @@ gmplibs
|
|||
HAVE_CXX11_FOR_BUILD
|
||||
HAVE_CXX11
|
||||
do_compare
|
||||
GDC
|
||||
GNATMAKE
|
||||
GNATBIND
|
||||
ac_ct_CXX
|
||||
|
@ -5625,6 +5627,106 @@ else
|
|||
have_gnat=no
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if test -n "$ac_tool_prefix"; then
|
||||
# Extract the first word of "${ac_tool_prefix}gdc", so it can be a program name with args.
|
||||
set dummy ${ac_tool_prefix}gdc; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if ${ac_cv_prog_GDC+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
if test -n "$GDC"; then
|
||||
ac_cv_prog_GDC="$GDC" # Let the user override the test.
|
||||
else
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_GDC="${ac_tool_prefix}gdc"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$as_save_IFS
|
||||
|
||||
fi
|
||||
fi
|
||||
GDC=$ac_cv_prog_GDC
|
||||
if test -n "$GDC"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $GDC" >&5
|
||||
$as_echo "$GDC" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
if test -z "$ac_cv_prog_GDC"; then
|
||||
ac_ct_GDC=$GDC
|
||||
# Extract the first word of "gdc", so it can be a program name with args.
|
||||
set dummy gdc; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if ${ac_cv_prog_ac_ct_GDC+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
if test -n "$ac_ct_GDC"; then
|
||||
ac_cv_prog_ac_ct_GDC="$ac_ct_GDC" # Let the user override the test.
|
||||
else
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_ac_ct_GDC="gdc"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$as_save_IFS
|
||||
|
||||
fi
|
||||
fi
|
||||
ac_ct_GDC=$ac_cv_prog_ac_ct_GDC
|
||||
if test -n "$ac_ct_GDC"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_GDC" >&5
|
||||
$as_echo "$ac_ct_GDC" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
if test "x$ac_ct_GDC" = x; then
|
||||
GDC="no"
|
||||
else
|
||||
case $cross_compiling:$ac_tool_warned in
|
||||
yes:)
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
|
||||
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
|
||||
ac_tool_warned=yes ;;
|
||||
esac
|
||||
GDC=$ac_ct_GDC
|
||||
fi
|
||||
else
|
||||
GDC="$ac_cv_prog_GDC"
|
||||
fi
|
||||
|
||||
if test "x$GDC" != xno; then
|
||||
have_gdc=yes
|
||||
else
|
||||
have_gdc=no
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to compare bootstrapped objects" >&5
|
||||
$as_echo_n "checking how to compare bootstrapped objects... " >&6; }
|
||||
if ${gcc_cv_prog_cmp_skip+:} false; then :
|
||||
|
@ -8679,6 +8781,23 @@ $as_echo "$as_me: WARNING: GNAT is required to build $language" >&2;}
|
|||
;;
|
||||
esac
|
||||
|
||||
# Disable D if no preexisting GDC is available.
|
||||
case ${add_this_lang}:${language}:${have_gdc} in
|
||||
yes:d:no)
|
||||
# Specifically requested language; tell them.
|
||||
as_fn_error $? "GDC is required to build $language" "$LINENO" 5
|
||||
;;
|
||||
all:d:no)
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: GDC is required to build $language" >&5
|
||||
$as_echo "$as_me: WARNING: GDC is required to build $language" >&2;}
|
||||
add_this_lang=unsupported
|
||||
;;
|
||||
*:d:no)
|
||||
# Silently disable.
|
||||
add_this_lang=unsupported
|
||||
;;
|
||||
esac
|
||||
|
||||
# Disable jit if -enable-host-shared not specified
|
||||
# but not if building for Mingw. All code in Windows
|
||||
# is position independent code (PIC).
|
||||
|
@ -8748,7 +8867,7 @@ $as_echo "$as_me: WARNING: ${language} not supported for this target" >&2;}
|
|||
*) stage1_languages="${stage1_languages}${language}," ;;
|
||||
esac
|
||||
# We need to bootstrap any supporting libraries.
|
||||
bootstrap_target_libs="${bootstrap_target_libs}${target_libs},"
|
||||
bootstrap_target_libs=`echo "${bootstrap_target_libs}${target_libs}," | sed "s/ /,/g"`
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
@ -9517,6 +9636,16 @@ if echo " ${target_configdirs} " | grep " libvtv " > /dev/null 2>&1 &&
|
|||
bootstrap_target_libs=${bootstrap_target_libs}target-libvtv,
|
||||
fi
|
||||
|
||||
# If we are building libatomic and the list of enabled languages includes the
|
||||
# D frontend, bootstrap it.
|
||||
if echo " ${target_configdirs} " | grep " libatomic " > /dev/null 2>&1; then
|
||||
case ,${enable_languages}, in
|
||||
*,d,*)
|
||||
bootstrap_target_libs=${bootstrap_target_libs}target-libatomic,
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Determine whether gdb needs tk/tcl or not.
|
||||
# Use 'maybe' since enable_gdbtk might be true even if tk isn't available
|
||||
# and in that case we want gdb to be built without tk. Ugh!
|
||||
|
@ -12614,6 +12743,8 @@ fi
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
# Target tools.
|
||||
|
||||
# Check whether --with-build-time-tools was given.
|
||||
|
|
31
configure.ac
31
configure.ac
|
@ -1406,6 +1406,7 @@ int main() {}])],
|
|||
fi
|
||||
|
||||
ACX_PROG_GNAT
|
||||
ACX_PROG_GDC
|
||||
ACX_PROG_CMP_IGNORE_INITIAL
|
||||
|
||||
AC_ARG_ENABLE([bootstrap],
|
||||
|
@ -2087,6 +2088,22 @@ if test -d ${srcdir}/gcc; then
|
|||
;;
|
||||
esac
|
||||
|
||||
# Disable D if no preexisting GDC is available.
|
||||
case ${add_this_lang}:${language}:${have_gdc} in
|
||||
yes:d:no)
|
||||
# Specifically requested language; tell them.
|
||||
AC_MSG_ERROR([GDC is required to build $language])
|
||||
;;
|
||||
all:d:no)
|
||||
AC_MSG_WARN([GDC is required to build $language])
|
||||
add_this_lang=unsupported
|
||||
;;
|
||||
*:d:no)
|
||||
# Silently disable.
|
||||
add_this_lang=unsupported
|
||||
;;
|
||||
esac
|
||||
|
||||
# Disable jit if -enable-host-shared not specified
|
||||
# but not if building for Mingw. All code in Windows
|
||||
# is position independent code (PIC).
|
||||
|
@ -2154,7 +2171,7 @@ directories, to avoid imposing the performance cost of
|
|||
*) stage1_languages="${stage1_languages}${language}," ;;
|
||||
esac
|
||||
# We need to bootstrap any supporting libraries.
|
||||
bootstrap_target_libs="${bootstrap_target_libs}${target_libs},"
|
||||
bootstrap_target_libs=`echo "${bootstrap_target_libs}${target_libs}," | sed "s/ /,/g"`
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
@ -2837,6 +2854,16 @@ if echo " ${target_configdirs} " | grep " libvtv " > /dev/null 2>&1 &&
|
|||
bootstrap_target_libs=${bootstrap_target_libs}target-libvtv,
|
||||
fi
|
||||
|
||||
# If we are building libatomic and the list of enabled languages includes the
|
||||
# D frontend, bootstrap it.
|
||||
if echo " ${target_configdirs} " | grep " libatomic " > /dev/null 2>&1; then
|
||||
case ,${enable_languages}, in
|
||||
*,d,*)
|
||||
bootstrap_target_libs=${bootstrap_target_libs}target-libatomic,
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Determine whether gdb needs tk/tcl or not.
|
||||
# Use 'maybe' since enable_gdbtk might be true even if tk isn't available
|
||||
# and in that case we want gdb to be built without tk. Ugh!
|
||||
|
@ -3505,6 +3532,8 @@ AC_SUBST(CC)
|
|||
AC_SUBST(CXX)
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(CXXFLAGS)
|
||||
AC_SUBST(GDC)
|
||||
AC_SUBST(GDCFLAGS)
|
||||
|
||||
# Target tools.
|
||||
AC_ARG_WITH([build-time-tools],
|
||||
|
|
|
@ -1092,6 +1092,10 @@ SYSLIBS = @GNAT_LIBEXC@
|
|||
GNATBIND = @GNATBIND@
|
||||
GNATMAKE = @GNATMAKE@
|
||||
|
||||
# Used from d/Make-lang.in
|
||||
GDC = @GDC@
|
||||
GDCFLAGS = @GDCFLAGS@
|
||||
|
||||
# Libs needed (at present) just for jcf-dump.
|
||||
LDEXP_LIB = @LDEXP_LIB@
|
||||
|
||||
|
|
107
gcc/configure
vendored
107
gcc/configure
vendored
|
@ -858,6 +858,8 @@ EGREP
|
|||
GREP
|
||||
CXXCPP
|
||||
PICFLAG_FOR_TARGET
|
||||
GDCFLAGS
|
||||
GDC
|
||||
GNATMAKE
|
||||
GNATBIND
|
||||
ac_ct_CXX
|
||||
|
@ -5257,6 +5259,106 @@ else
|
|||
fi
|
||||
|
||||
|
||||
|
||||
if test -n "$ac_tool_prefix"; then
|
||||
# Extract the first word of "${ac_tool_prefix}gdc", so it can be a program name with args.
|
||||
set dummy ${ac_tool_prefix}gdc; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if ${ac_cv_prog_GDC+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
if test -n "$GDC"; then
|
||||
ac_cv_prog_GDC="$GDC" # Let the user override the test.
|
||||
else
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_GDC="${ac_tool_prefix}gdc"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$as_save_IFS
|
||||
|
||||
fi
|
||||
fi
|
||||
GDC=$ac_cv_prog_GDC
|
||||
if test -n "$GDC"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $GDC" >&5
|
||||
$as_echo "$GDC" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
if test -z "$ac_cv_prog_GDC"; then
|
||||
ac_ct_GDC=$GDC
|
||||
# Extract the first word of "gdc", so it can be a program name with args.
|
||||
set dummy gdc; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if ${ac_cv_prog_ac_ct_GDC+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
if test -n "$ac_ct_GDC"; then
|
||||
ac_cv_prog_ac_ct_GDC="$ac_ct_GDC" # Let the user override the test.
|
||||
else
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_ac_ct_GDC="gdc"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$as_save_IFS
|
||||
|
||||
fi
|
||||
fi
|
||||
ac_ct_GDC=$ac_cv_prog_ac_ct_GDC
|
||||
if test -n "$ac_ct_GDC"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_GDC" >&5
|
||||
$as_echo "$ac_ct_GDC" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
if test "x$ac_ct_GDC" = x; then
|
||||
GDC="no"
|
||||
else
|
||||
case $cross_compiling:$ac_tool_warned in
|
||||
yes:)
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
|
||||
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
|
||||
ac_tool_warned=yes ;;
|
||||
esac
|
||||
GDC=$ac_ct_GDC
|
||||
fi
|
||||
else
|
||||
GDC="$ac_cv_prog_GDC"
|
||||
fi
|
||||
|
||||
if test "x$GDC" != xno; then
|
||||
have_gdc=yes
|
||||
else
|
||||
have_gdc=no
|
||||
fi
|
||||
|
||||
|
||||
# Do configure tests with the C++ compiler, since that's what we build with.
|
||||
ac_ext=cpp
|
||||
ac_cpp='$CXXCPP $CPPFLAGS'
|
||||
|
@ -5275,6 +5377,7 @@ esac
|
|||
|
||||
|
||||
|
||||
|
||||
# Determine PICFLAG for target gnatlib.
|
||||
|
||||
|
||||
|
@ -19458,7 +19561,7 @@ else
|
|||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 19461 "configure"
|
||||
#line 19564 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
|
@ -19564,7 +19667,7 @@ else
|
|||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 19567 "configure"
|
||||
#line 19670 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
|
|
|
@ -435,6 +435,7 @@ rm -f a.out a.exe b.out
|
|||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
ACX_PROG_GNAT([-I"$srcdir"/ada/libgnat])
|
||||
ACX_PROG_GDC([-I"$srcdir"/d])
|
||||
|
||||
# Do configure tests with the C++ compiler, since that's what we build with.
|
||||
AC_LANG(C++)
|
||||
|
@ -448,6 +449,7 @@ case "$CC" in
|
|||
esac
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(CXXFLAGS)
|
||||
AC_SUBST(GDCFLAGS)
|
||||
|
||||
# Determine PICFLAG for target gnatlib.
|
||||
GCC_PICFLAG_FOR_TARGET
|
||||
|
|
|
@ -46,30 +46,61 @@ gdc-cross$(exeext): gdc$(exeext)
|
|||
-rm -f gdc-cross$(exeext)
|
||||
cp gdc$(exeext) gdc-cross$(exeext)
|
||||
|
||||
# Filter out pedantic and virtual overload warnings.
|
||||
d-warn = $(filter-out -pedantic -Woverloaded-virtual, $(STRICT_WARN))
|
||||
# Use strict warnings.
|
||||
d-warn = $(STRICT_WARN)
|
||||
|
||||
# Also filter out warnings for missing format attributes in the D Frontend.
|
||||
DMD_WARN_CXXFLAGS = $(filter-out -Wmissing-format-attribute, $(WARN_CXXFLAGS))
|
||||
DMD_COMPILE = $(subst $(WARN_CXXFLAGS), $(DMD_WARN_CXXFLAGS), $(COMPILE))
|
||||
# D compiler and flags for building the front-end.
|
||||
ifeq ($(TREECHECKING),)
|
||||
CHECKING_DFLAGS = -frelease
|
||||
else
|
||||
CHECKING_DFLAGS =
|
||||
endif
|
||||
WARN_DFLAGS = -Wall -Wdeprecated $(NOCOMMON_FLAG)
|
||||
|
||||
ALL_DFLAGS = $(DFLAGS-$@) $(GDCFLAGS) -fversion=IN_GCC $(CHECKING_DFLAGS) \
|
||||
$(PICFLAG) $(ALIASING_FLAGS) $(COVERAGE_FLAGS) $(WARN_DFLAGS)
|
||||
|
||||
DCOMPILE.base = $(GDC) $(NO_PIE_CFLAGS) -c $(ALL_DFLAGS) -o $@
|
||||
DCOMPILE = $(DCOMPILE.base) -MT $@ -MMD -MP -MF $(@D)/$(DEPDIR)/$(*F).TPo
|
||||
DPOSTCOMPILE = @mv $(@D)/$(DEPDIR)/$(*F).TPo $(@D)/$(DEPDIR)/$(*F).Po
|
||||
DLINKER = $(GDC) $(NO_PIE_FLAG) -lstdc++
|
||||
|
||||
# Like LINKER, but use a mutex for serializing front end links.
|
||||
ifeq (@DO_LINK_MUTEX@,true)
|
||||
DLLINKER = $(SHELL) $(srcdir)/lock-and-run.sh linkfe.lck $(DLINKER)
|
||||
else
|
||||
DLLINKER = $(DLINKER)
|
||||
endif
|
||||
|
||||
# D Frontend object files.
|
||||
D_FRONTEND_OBJS = \
|
||||
d/aav.o \
|
||||
d/access.o \
|
||||
d/aggregate.o \
|
||||
d/aliasthis.o \
|
||||
d/apply.o \
|
||||
d/array.o \
|
||||
d/arrayop.o \
|
||||
d/arraytypes.o \
|
||||
d/attrib.o \
|
||||
d/ast_node.o \
|
||||
d/astcodegen.o \
|
||||
d/astenums.o \
|
||||
d/bitarray.o \
|
||||
d/blockexit.o \
|
||||
d/builtin.o \
|
||||
d/canthrow.o \
|
||||
d/checkedint.o \
|
||||
d/chkformat.o \
|
||||
d/clone.o \
|
||||
d/compiler.o \
|
||||
d/complex.o \
|
||||
d/cond.o \
|
||||
d/constfold.o \
|
||||
d/cparse.o \
|
||||
d/cppmangle.o \
|
||||
d/ctfeexpr.o \
|
||||
d/ctfloat.o \
|
||||
d/ctorflow.o \
|
||||
d/dcast.o \
|
||||
d/dclass.o \
|
||||
d/declaration.o \
|
||||
|
@ -86,32 +117,49 @@ D_FRONTEND_OBJS = \
|
|||
d/dsymbol.o \
|
||||
d/dsymbolsem.o \
|
||||
d/dtemplate.o \
|
||||
d/dtoh.o \
|
||||
d/dversion.o \
|
||||
d/entity.o \
|
||||
d/errors.o \
|
||||
d/escape.o \
|
||||
d/expression.o \
|
||||
d/expressionsem.o \
|
||||
d/file.o \
|
||||
d/filename.o \
|
||||
d/foreachvar.o \
|
||||
d/func.o \
|
||||
d/globals.o \
|
||||
d/gluelayer.o \
|
||||
d/hash.o \
|
||||
d/hdrgen.o \
|
||||
d/iasm.o \
|
||||
d/iasmgcc.o \
|
||||
d/id.o \
|
||||
d/identifier.o \
|
||||
d/impcnvtab.o \
|
||||
d/imphint.o \
|
||||
d/init.o \
|
||||
d/initsem.o \
|
||||
d/inline.o \
|
||||
d/intrange.o \
|
||||
d/json.o \
|
||||
d/lambdacomp.o \
|
||||
d/lexer.o \
|
||||
d/longdouble.o \
|
||||
d/mtype.o \
|
||||
d/nogc.o \
|
||||
d/nspace.o \
|
||||
d/ob.o \
|
||||
d/objc.o \
|
||||
d/opover.o \
|
||||
d/optimize.o \
|
||||
d/outbuffer.o \
|
||||
d/parse.o \
|
||||
d/parsetimevisitor.o \
|
||||
d/permissivevisitor.o \
|
||||
d/port.o \
|
||||
d/printast.o \
|
||||
d/region.o \
|
||||
d/rmem.o \
|
||||
d/rootobject.o \
|
||||
d/safe.o \
|
||||
|
@ -121,20 +169,23 @@ D_FRONTEND_OBJS = \
|
|||
d/sideeffect.o \
|
||||
d/speller.o \
|
||||
d/statement.o \
|
||||
d/statement_rewrite_walker.o \
|
||||
d/statementsem.o \
|
||||
d/staticassert.o \
|
||||
d/staticcond.o \
|
||||
d/stmtstate.o \
|
||||
d/string.o \
|
||||
d/stringtable.o \
|
||||
d/target.o \
|
||||
d/templateparamsem.o \
|
||||
d/tokens.o \
|
||||
d/traits.o \
|
||||
d/transitivevisitor.o \
|
||||
d/typesem.o \
|
||||
d/typinf.o \
|
||||
d/utf.o \
|
||||
d/utils.o
|
||||
|
||||
# D Frontend generated files.
|
||||
D_GENERATED_SRCS = d/id.c d/id.h d/impcnvtab.c
|
||||
D_GENERATED_OBJS = d/id.o d/impcnvtab.o
|
||||
d/utils.o \
|
||||
d/visitor.o
|
||||
|
||||
# Language-specific object files for D.
|
||||
D_OBJS = \
|
||||
|
@ -163,13 +214,13 @@ D_OBJS = \
|
|||
d/types.o
|
||||
|
||||
# All language-specific object files for D.
|
||||
D_ALL_OBJS = $(D_FRONTEND_OBJS) $(D_GENERATED_OBJS) $(D_OBJS) $(D_TARGET_OBJS)
|
||||
D_ALL_OBJS = $(D_FRONTEND_OBJS) $(D_OBJS) $(D_TARGET_OBJS)
|
||||
|
||||
d_OBJS = $(D_ALL_OBJS) d/d-spec.o
|
||||
|
||||
d21$(exeext): $(D_ALL_OBJS) attribs.o $(BACKEND) $(LIBDEPS) $(d.prev)
|
||||
@$(call LINK_PROGRESS,$(INDEX.d),start)
|
||||
+$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
|
||||
+$(DLLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -static-libphobos -o $@ \
|
||||
$(D_ALL_OBJS) attribs.o $(BACKEND) $(LIBS) $(BACKENDLIBS)
|
||||
@$(call LINK_PROGRESS,$(INDEX.d),end)
|
||||
|
||||
|
@ -221,7 +272,7 @@ d.srcextra:
|
|||
|
||||
d.tags: force
|
||||
cd $(srcdir)/d; \
|
||||
$(ETAGS) -o TAGS.sub *.c *.cc *.h dmd/*.c dmd/*.h dmd/root/*.h dmd/root/*.c; \
|
||||
$(ETAGS) -o TAGS.sub *.c *.cc *.h dmd/*.h dmd/root/*.h; \
|
||||
$(ETAGS) --include TAGS.sub --include ../TAGS.sub
|
||||
|
||||
d.man: doc/gdc.1
|
||||
|
@ -313,8 +364,6 @@ d.uninstall:
|
|||
d.mostlyclean:
|
||||
-rm -f d/*$(objext)
|
||||
-rm -f d/*$(coverageexts)
|
||||
-rm -f $(D_GENERATED_SRCS)
|
||||
-rm -f d/idgen$(build_exeext) d/impcnvgen$(build_exeext)
|
||||
-rm -f gdc$(exeext) gdc-cross$(exeext) d21$(exeext)
|
||||
d.clean:
|
||||
d.distclean:
|
||||
|
@ -337,48 +386,13 @@ d.stagefeedback: stagefeedback-start
|
|||
-mv d/*$(objext) stagefeedback/d
|
||||
|
||||
# Include the dfrontend and build directories for headers.
|
||||
D_INCLUDES = -I$(srcdir)/d -I$(srcdir)/d/dmd -Id
|
||||
|
||||
CFLAGS-d/id.o += $(D_INCLUDES)
|
||||
CFLAGS-d/impcnvtab.o += $(D_INCLUDES)
|
||||
D_INCLUDES = -I$(srcdir)/d -J$(srcdir)/d/dmd -J$(srcdir)/d/dmd/res
|
||||
|
||||
# Override build rules for D frontend.
|
||||
d/%.o: d/dmd/%.c $(D_GENERATED_SRCS)
|
||||
$(DMD_COMPILE) $(D_INCLUDES) $<
|
||||
$(POSTCOMPILE)
|
||||
d/%.o: d/dmd/%.d
|
||||
$(DCOMPILE) $(D_INCLUDES) $<
|
||||
$(DPOSTCOMPILE)
|
||||
|
||||
d/%.o: d/dmd/root/%.c $(D_GENERATED_SRCS)
|
||||
$(DMD_COMPILE) $(D_INCLUDES) $<
|
||||
$(POSTCOMPILE)
|
||||
|
||||
# Generated programs.
|
||||
d/idgen$(build_exeext): d/idgen.dmdgen.o $(BUILD_LIBDEPS)
|
||||
+$(LINKER_FOR_BUILD) $(BUILD_LINKERFLAGS) $(BUILD_LDFLAGS) -o $@ \
|
||||
$(filter-out $(BUILD_LIBDEPS), $^) $(BUILD_LIBS)
|
||||
|
||||
d/impcnvgen$(build_exeext): d/impcnvgen.dmdgen.o $(BUILD_LIBDEPS)
|
||||
+$(LINKER_FOR_BUILD) $(BUILD_LINKERFLAGS) $(BUILD_LDFLAGS) -o $@ \
|
||||
$(filter-out $(BUILD_LIBDEPS), $^) $(BUILD_LIBS)
|
||||
|
||||
# Generated sources.
|
||||
d/id.c: d/idgen$(build_exeext)
|
||||
cd d && ./idgen$(build_exeext)
|
||||
|
||||
# idgen also generates id.h; just verify it exists.
|
||||
d/id.h: d/id.c
|
||||
|
||||
d/impcnvtab.c: d/impcnvgen$(build_exeext)
|
||||
cd d && ./impcnvgen$(build_exeext)
|
||||
|
||||
# Compile the generator programs.
|
||||
d/%.dmdgen.o: $(srcdir)/d/dmd/%.c
|
||||
$(COMPILER_FOR_BUILD) -c $(BUILD_COMPILERFLAGS) $(D_INCLUDES) \
|
||||
$(BUILD_CPPFLAGS) -o $@ $<
|
||||
|
||||
# Header dependencies for the generator programs.
|
||||
D_SYSTEM_H = d/dmd/root/dsystem.h d/d-system.h
|
||||
|
||||
d/idgen.dmdgen.o: d/dmd/idgen.c $(D_SYSTEM_H) $(BCONFIG_H) $(SYSTEM_H)
|
||||
|
||||
d/impcnvgen.dmdgen.o: d/dmd/impcnvgen.c d/dmd/mtype.h $(D_SYSTEM_H) \
|
||||
$(BCONFIG_H) $(SYSTEM_H)
|
||||
d/%.o: d/dmd/root/%.d
|
||||
$(DCOMPILE) $(D_INCLUDES) $<
|
||||
$(DPOSTCOMPILE)
|
||||
|
|
|
@ -19,10 +19,12 @@
|
|||
# We define several parameters used by configure:
|
||||
#
|
||||
# language - name of language as it would appear in $(LANGUAGES)
|
||||
# boot_language - "yes" if we need to build this language in stage1
|
||||
# compilers - value to add to $(COMPILERS)
|
||||
|
||||
language="d"
|
||||
|
||||
boot_language=yes
|
||||
compilers="d21\$(exeext)"
|
||||
|
||||
phobos_target_deps="target-zlib target-libbacktrace"
|
||||
|
|
|
@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "dmd/attrib.h"
|
||||
#include "dmd/declaration.h"
|
||||
#include "dmd/expression.h"
|
||||
#include "dmd/module.h"
|
||||
#include "dmd/mtype.h"
|
||||
#include "dmd/template.h"
|
||||
|
|
|
@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "stor-layout.h"
|
||||
|
||||
#include "d-tree.h"
|
||||
#include "d-frontend.h"
|
||||
#include "d-target.h"
|
||||
|
||||
|
||||
|
@ -98,7 +99,7 @@ build_frontend_type (tree type)
|
|||
if (TYPE_MAIN_VARIANT (TREE_TYPE (type)) == char_type_node)
|
||||
return Type::tchar->addMod (dtype->mod)->pointerTo ()->addMod (mod);
|
||||
|
||||
if (dtype->ty == Tfunction)
|
||||
if (dtype->ty == TY::Tfunction)
|
||||
return (TypePointer::create (dtype))->addMod (mod);
|
||||
|
||||
return dtype->pointerTo ()->addMod (mod);
|
||||
|
@ -130,7 +131,7 @@ build_frontend_type (tree type)
|
|||
|
||||
/* For now, skip support for cent/ucent until the frontend
|
||||
has better support for handling it. */
|
||||
for (size_t i = Tint8; i <= Tuns64; i++)
|
||||
for (size_t i = (size_t) TY::Tint8; i <= (size_t) TY::Tuns64; i++)
|
||||
{
|
||||
dtype = Type::basic[i];
|
||||
|
||||
|
@ -148,7 +149,7 @@ build_frontend_type (tree type)
|
|||
{
|
||||
unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
|
||||
|
||||
for (size_t i = Tfloat32; i <= Tfloat80; i++)
|
||||
for (size_t i = (size_t) TY::Tfloat32; i <= (size_t) TY::Tfloat80; i++)
|
||||
{
|
||||
dtype = Type::basic[i];
|
||||
|
||||
|
@ -164,7 +165,8 @@ build_frontend_type (tree type)
|
|||
case COMPLEX_TYPE:
|
||||
{
|
||||
unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
|
||||
for (size_t i = Tcomplex32; i <= Tcomplex80; i++)
|
||||
for (size_t i = (size_t) TY::Tcomplex32; i <= (size_t) TY::Tcomplex80;
|
||||
i++)
|
||||
{
|
||||
dtype = Type::basic[i];
|
||||
|
||||
|
@ -235,7 +237,7 @@ build_frontend_type (tree type)
|
|||
sdecl->structsize = int_size_in_bytes (type);
|
||||
sdecl->alignsize = TYPE_ALIGN_UNIT (type);
|
||||
sdecl->alignment = STRUCTALIGN_DEFAULT;
|
||||
sdecl->sizeok = SIZEOKdone;
|
||||
sdecl->sizeok = Sizeok::done;
|
||||
sdecl->type = (TypeStruct::create (sdecl))->addMod (mod);
|
||||
sdecl->type->ctype = type;
|
||||
sdecl->type->merge2 ();
|
||||
|
@ -243,7 +245,7 @@ build_frontend_type (tree type)
|
|||
/* Add both named and anonymous fields as members of the struct.
|
||||
Anonymous fields still need a name in D, so call them "__pad%u". */
|
||||
unsigned anonfield_id = 0;
|
||||
sdecl->members = new Dsymbols;
|
||||
sdecl->members = d_gc_malloc<Dsymbols> ();
|
||||
|
||||
for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
|
||||
{
|
||||
|
@ -253,7 +255,6 @@ build_frontend_type (tree type)
|
|||
/* Drop any field types that got cached before the conversion
|
||||
of this record type failed. */
|
||||
builtin_converted_decls.truncate (saved_builtin_decls_length);
|
||||
delete sdecl->members;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -292,7 +293,7 @@ build_frontend_type (tree type)
|
|||
tree parms = TYPE_ARG_TYPES (type);
|
||||
VarArg varargs_p = VARARGvariadic;
|
||||
|
||||
Parameters *args = new Parameters;
|
||||
Parameters *args = d_gc_malloc<Parameters> ();
|
||||
args->reserve (list_length (parms));
|
||||
|
||||
/* Attempt to convert all parameter types. */
|
||||
|
@ -318,7 +319,6 @@ build_frontend_type (tree type)
|
|||
/* Drop any parameter types that got cached before the
|
||||
conversion of this function type failed. */
|
||||
builtin_converted_decls.truncate (saved_builtin_decls_length);
|
||||
delete args;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -329,7 +329,7 @@ build_frontend_type (tree type)
|
|||
have no named parameters, and so can't be represented in D. */
|
||||
if (args->length != 0 || varargs_p == VARARGnone)
|
||||
{
|
||||
dtype = TypeFunction::create (args, dtype, varargs_p, LINKc);
|
||||
dtype = TypeFunction::create (args, dtype, varargs_p, LINK::c);
|
||||
return dtype->addMod (mod);
|
||||
}
|
||||
}
|
||||
|
@ -386,7 +386,7 @@ d_eval_constant_expression (const Loc &loc, tree cst)
|
|||
else if (code == VECTOR_CST)
|
||||
{
|
||||
dinteger_t nunits = VECTOR_CST_NELTS (cst).to_constant ();
|
||||
Expressions *elements = new Expressions;
|
||||
Expressions *elements = d_gc_malloc<Expressions> ();
|
||||
elements->setDim (nunits);
|
||||
|
||||
for (size_t i = 0; i < nunits; i++)
|
||||
|
@ -520,7 +520,7 @@ build_alias_declaration (const char *alias, Type *type)
|
|||
void
|
||||
d_build_builtins_module (Module *m)
|
||||
{
|
||||
Dsymbols *members = new Dsymbols;
|
||||
Dsymbols *members = d_gc_malloc<Dsymbols> ();
|
||||
tree decl;
|
||||
|
||||
for (size_t i = 0; vec_safe_iterate (gcc_builtins_functions, i, &decl); ++i)
|
||||
|
@ -543,16 +543,16 @@ d_build_builtins_module (Module *m)
|
|||
flag_unsafe_math_optimizations.
|
||||
- Built-ins never use the GC or raise a D exception, and so are always
|
||||
marked as `nothrow' and `@nogc'. */
|
||||
tf->purity = DECL_PURE_P (decl) ? PUREstrong
|
||||
: TREE_READONLY (decl) ? PUREconst
|
||||
: DECL_IS_NOVOPS (decl) ? PUREweak
|
||||
: !DECL_ASSEMBLER_NAME_SET_P (decl) ? PUREweak
|
||||
: PUREimpure;
|
||||
tf->trust = !DECL_ASSEMBLER_NAME_SET_P (decl) ? TRUSTsafe
|
||||
: TREE_NOTHROW (decl) ? TRUSTtrusted
|
||||
: TRUSTsystem;
|
||||
tf->isnothrow = true;
|
||||
tf->isnogc = true;
|
||||
tf->purity = DECL_PURE_P (decl) ? PURE::strong
|
||||
: TREE_READONLY (decl) ? PURE::const_
|
||||
: DECL_IS_NOVOPS (decl) ? PURE::weak
|
||||
: !DECL_ASSEMBLER_NAME_SET_P (decl) ? PURE::weak
|
||||
: PURE::impure;
|
||||
tf->trust = !DECL_ASSEMBLER_NAME_SET_P (decl) ? TRUST::safe
|
||||
: TREE_NOTHROW (decl) ? TRUST::trusted
|
||||
: TRUST::system;
|
||||
tf->isnothrow (true);
|
||||
tf->isnogc (true);
|
||||
|
||||
FuncDeclaration *func
|
||||
= FuncDeclaration::create (Loc (), Loc (),
|
||||
|
@ -560,7 +560,7 @@ d_build_builtins_module (Module *m)
|
|||
STCextern, tf);
|
||||
DECL_LANG_SPECIFIC (decl) = build_lang_decl (func);
|
||||
func->csym = decl;
|
||||
func->builtin = BUILTINgcc;
|
||||
func->builtin = BUILTIN::gcc;
|
||||
|
||||
members->push (func);
|
||||
}
|
||||
|
@ -660,7 +660,7 @@ d_build_builtins_module (Module *m)
|
|||
members->push (build_alias_declaration ("__builtin_unwind_uint", t));
|
||||
}
|
||||
|
||||
m->members->push (LinkDeclaration::create (LINKc, members));
|
||||
m->members->push (LinkDeclaration::create (Loc (), LINK::c, members));
|
||||
}
|
||||
|
||||
/* Search for any `extern(C)' functions that match any known GCC library builtin
|
||||
|
@ -700,7 +700,7 @@ maybe_set_builtin_1 (Dsymbol *d)
|
|||
/* Found a match, tell the frontend this is a builtin. */
|
||||
DECL_LANG_SPECIFIC (t) = build_lang_decl (fd);
|
||||
fd->csym = t;
|
||||
fd->builtin = BUILTINgcc;
|
||||
fd->builtin = BUILTIN::gcc;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -858,7 +858,7 @@ d_build_d_type_nodes (void)
|
|||
|
||||
/* Calling build_ctype() links the front-end Type to the GCC node,
|
||||
and sets the TYPE_NAME to the D language type. */
|
||||
for (unsigned ty = 0; ty < TMAX; ty++)
|
||||
for (unsigned ty = 0; ty < (unsigned) TY::TMAX; ty++)
|
||||
{
|
||||
if (Type::basic[ty] != NULL)
|
||||
build_ctype (Type::basic[ty]);
|
||||
|
|
|
@ -76,7 +76,7 @@ d_decl_context (Dsymbol *dsym)
|
|||
but only for extern(D) symbols. */
|
||||
if (parent->isModule ())
|
||||
{
|
||||
if ((decl != NULL && decl->linkage != LINKd)
|
||||
if ((decl != NULL && decl->linkage != LINK::d)
|
||||
|| (ad != NULL && ad->classKind != ClassKind::d))
|
||||
return NULL_TREE;
|
||||
|
||||
|
@ -131,7 +131,7 @@ declaration_reference_p (Declaration *decl)
|
|||
Type *tb = decl->type->toBasetype ();
|
||||
|
||||
/* Declaration is a reference type. */
|
||||
if (tb->ty == Treference || decl->storage_class & (STCout | STCref))
|
||||
if (tb->ty == TY::Treference || decl->storage_class & (STCout | STCref))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -146,7 +146,7 @@ declaration_type (Declaration *decl)
|
|||
if (decl->storage_class & STClazy)
|
||||
{
|
||||
TypeFunction *tf = TypeFunction::create (NULL, decl->type,
|
||||
VARARGnone, LINKd);
|
||||
VARARGnone, LINK::d);
|
||||
TypeDelegate *t = TypeDelegate::create (tf);
|
||||
return build_ctype (t->merge2 ());
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ parameter_reference_p (Parameter *arg)
|
|||
Type *tb = arg->type->toBasetype ();
|
||||
|
||||
/* Parameter is a reference type. */
|
||||
if (tb->ty == Treference || arg->storageClass & (STCout | STCref))
|
||||
if (tb->ty == TY::Treference || arg->storageClass & (STCout | STCref))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -196,7 +196,7 @@ parameter_type (Parameter *arg)
|
|||
if (arg->storageClass & STClazy)
|
||||
{
|
||||
TypeFunction *tf = TypeFunction::create (NULL, arg->type,
|
||||
VARARGnone, LINKd);
|
||||
VARARGnone, LINK::d);
|
||||
TypeDelegate *t = TypeDelegate::create (tf);
|
||||
return build_ctype (t->merge2 ());
|
||||
}
|
||||
|
@ -319,10 +319,10 @@ get_array_length (tree exp, Type *type)
|
|||
|
||||
switch (tb->ty)
|
||||
{
|
||||
case Tsarray:
|
||||
case TY::Tsarray:
|
||||
return size_int (tb->isTypeSArray ()->dim->toUInteger ());
|
||||
|
||||
case Tarray:
|
||||
case TY::Tarray:
|
||||
return d_array_length (exp);
|
||||
|
||||
default:
|
||||
|
@ -411,7 +411,7 @@ build_delegate_cst (tree method, tree object, Type *type)
|
|||
tree ctype;
|
||||
|
||||
Type *tb = type->toBasetype ();
|
||||
if (tb->ty == Tdelegate)
|
||||
if (tb->ty == TY::Tdelegate)
|
||||
ctype = build_ctype (type);
|
||||
else
|
||||
{
|
||||
|
@ -464,11 +464,11 @@ build_typeof_null_value (Type *type)
|
|||
tree value;
|
||||
|
||||
/* For dynamic arrays, set length and pointer fields to zero. */
|
||||
if (tb->ty == Tarray)
|
||||
if (tb->ty == TY::Tarray)
|
||||
value = d_array_value (build_ctype (type), size_int (0), null_pointer_node);
|
||||
|
||||
/* For associative arrays, set the pointer field to null. */
|
||||
else if (tb->ty == Taarray)
|
||||
else if (tb->ty == TY::Taarray)
|
||||
{
|
||||
tree ctype = build_ctype (type);
|
||||
gcc_assert (TYPE_ASSOCIATIVE_ARRAY (ctype));
|
||||
|
@ -478,7 +478,7 @@ build_typeof_null_value (Type *type)
|
|||
}
|
||||
|
||||
/* For delegates, set the frame and function pointer fields to null. */
|
||||
else if (tb->ty == Tdelegate)
|
||||
else if (tb->ty == TY::Tdelegate)
|
||||
value = build_delegate_cst (null_pointer_node, null_pointer_node, type);
|
||||
|
||||
/* Simple zero constant for all other types. */
|
||||
|
@ -882,7 +882,9 @@ identity_compare_p (StructDeclaration *sd)
|
|||
}
|
||||
|
||||
/* Check for types that may have padding. */
|
||||
if ((tb->ty == Tcomplex80 || tb->ty == Tfloat80 || tb->ty == Timaginary80)
|
||||
if ((tb->ty == TY::Tcomplex80
|
||||
|| tb->ty == TY::Tfloat80
|
||||
|| tb->ty == TY::Timaginary80)
|
||||
&& target.realpad != 0)
|
||||
return false;
|
||||
|
||||
|
@ -960,12 +962,12 @@ lower_struct_comparison (tree_code code, StructDeclaration *sd,
|
|||
/* Compare inner data structures. */
|
||||
tcmp = lower_struct_comparison (code, ts->sym, t1ref, t2ref);
|
||||
}
|
||||
else if (type->ty != Tvector && type->isintegral ())
|
||||
else if (type->ty != TY::Tvector && type->isintegral ())
|
||||
{
|
||||
/* Integer comparison, no special handling required. */
|
||||
tcmp = build_boolop (code, t1ref, t2ref);
|
||||
}
|
||||
else if (type->ty != Tvector && type->isfloating ())
|
||||
else if (type->ty != TY::Tvector && type->isfloating ())
|
||||
{
|
||||
/* Floating-point comparison, don't compare padding in type. */
|
||||
if (!type->iscomplex ())
|
||||
|
@ -1839,7 +1841,7 @@ static tree
|
|||
build_filename_from_loc (const Loc &loc)
|
||||
{
|
||||
const char *filename = loc.filename
|
||||
? loc.filename : d_function_chain->module->srcfile->toChars ();
|
||||
? loc.filename : d_function_chain->module->srcfile.toChars ();
|
||||
|
||||
unsigned length = strlen (filename);
|
||||
tree str = build_string (length, filename);
|
||||
|
@ -1862,7 +1864,6 @@ build_assert_call (const Loc &loc, libcall_fn libcall, tree msg)
|
|||
{
|
||||
case LIBCALL_ASSERT_MSG:
|
||||
case LIBCALL_UNITTEST_MSG:
|
||||
case LIBCALL_SWITCH_ERROR:
|
||||
/* File location is passed as a D string. */
|
||||
if (loc.filename)
|
||||
{
|
||||
|
@ -1912,7 +1913,7 @@ build_array_bounds_call (const Loc &loc)
|
|||
|
||||
/* Builds a bounds condition checking that INDEX is between 0 and LENGTH
|
||||
in the index expression IE. The condition returns the INDEX if true, or
|
||||
throws a `RangeError`. */
|
||||
throws a `ArrayIndexError`. */
|
||||
|
||||
tree
|
||||
build_bounds_index_condition (IndexExp *ie, tree index, tree length)
|
||||
|
@ -1927,7 +1928,16 @@ build_bounds_index_condition (IndexExp *ie, tree index, tree length)
|
|||
No need to check whether INDEX >= 0 as the front-end should
|
||||
have already taken care of implicit casts to unsigned. */
|
||||
tree condition = fold_build2 (GE_EXPR, d_bool_type, index, length);
|
||||
tree boundserr = build_array_bounds_call (ie->e2->loc);
|
||||
tree boundserr;
|
||||
|
||||
if (checkaction_trap_p ())
|
||||
boundserr = build_call_expr (builtin_decl_explicit (BUILT_IN_TRAP), 0);
|
||||
else
|
||||
{
|
||||
boundserr = build_libcall (LIBCALL_ARRAYBOUNDS_INDEXP, Type::tvoid, 4,
|
||||
build_filename_from_loc (ie->e2->loc),
|
||||
size_int (ie->e2->loc.linnum), index, length);
|
||||
}
|
||||
|
||||
return build_condition (TREE_TYPE (index), condition, boundserr, index);
|
||||
}
|
||||
|
@ -1963,7 +1973,22 @@ build_bounds_slice_condition (SliceExp *se, tree lower, tree upper, tree length)
|
|||
|
||||
if (condition != NULL_TREE)
|
||||
{
|
||||
tree boundserr = build_array_bounds_call (se->loc);
|
||||
tree boundserr;
|
||||
|
||||
if (checkaction_trap_p ())
|
||||
{
|
||||
boundserr =
|
||||
build_call_expr (builtin_decl_explicit (BUILT_IN_TRAP), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
boundserr = build_libcall (LIBCALL_ARRAYBOUNDS_SLICEP,
|
||||
Type::tvoid, 5,
|
||||
build_filename_from_loc (se->loc),
|
||||
size_int (se->loc.linnum),
|
||||
lower, upper, length);
|
||||
}
|
||||
|
||||
upper = build_condition (TREE_TYPE (upper), condition,
|
||||
boundserr, upper);
|
||||
}
|
||||
|
@ -1993,9 +2018,9 @@ array_bounds_check (void)
|
|||
case CHECKENABLEsafeonly:
|
||||
/* For D2 safe functions only. */
|
||||
fd = d_function_chain->function;
|
||||
if (fd && fd->type->ty == Tfunction)
|
||||
if (fd && fd->type->ty == TY::Tfunction)
|
||||
{
|
||||
if (fd->type->isTypeFunction ()->trust == TRUSTsafe)
|
||||
if (fd->type->isTypeFunction ()->trust == TRUST::safe)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -2014,6 +2039,7 @@ checkaction_trap_p (void)
|
|||
switch (global.params.checkAction)
|
||||
{
|
||||
case CHECKACTION_D:
|
||||
case CHECKACTION_context:
|
||||
return false;
|
||||
|
||||
case CHECKACTION_C:
|
||||
|
@ -2032,11 +2058,11 @@ TypeFunction *
|
|||
get_function_type (Type *t)
|
||||
{
|
||||
TypeFunction *tf = NULL;
|
||||
if (t->ty == Tpointer)
|
||||
if (t->ty == TY::Tpointer)
|
||||
t = t->nextOf ()->toBasetype ();
|
||||
if (t->ty == Tfunction)
|
||||
if (t->ty == TY::Tfunction)
|
||||
tf = t->isTypeFunction ();
|
||||
else if (t->ty == Tdelegate)
|
||||
else if (t->ty == TY::Tdelegate)
|
||||
tf = t->isTypeDelegate ()->next->isTypeFunction ();
|
||||
return tf;
|
||||
}
|
||||
|
@ -2096,7 +2122,7 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
|
|||
|
||||
gcc_assert (FUNC_OR_METHOD_TYPE_P (ctype));
|
||||
gcc_assert (tf != NULL);
|
||||
gcc_assert (tf->ty == Tfunction);
|
||||
gcc_assert (tf->ty == TY::Tfunction);
|
||||
|
||||
if (TREE_CODE (ctype) != FUNCTION_TYPE && object == NULL_TREE)
|
||||
{
|
||||
|
@ -2195,7 +2221,7 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
|
|||
SET_EXPR_LOCATION (result, input_location);
|
||||
|
||||
/* Enforce left to right evaluation. */
|
||||
if (tf->linkage == LINKd)
|
||||
if (tf->linkage == LINK::d)
|
||||
CALL_EXPR_ARGS_ORDERED (result) = 1;
|
||||
|
||||
result = maybe_expand_intrinsic (result);
|
||||
|
|
|
@ -20,7 +20,6 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "coretypes.h"
|
||||
|
||||
#include "dmd/compiler.h"
|
||||
#include "dmd/scope.h"
|
||||
#include "dmd/expression.h"
|
||||
#include "dmd/identifier.h"
|
||||
#include "dmd/module.h"
|
||||
|
@ -34,40 +33,6 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
/* Implements the Compiler interface used by the frontend. */
|
||||
|
||||
/* Generate C main() in response to seeing D main(). This used to be in
|
||||
libdruntime, but contained a reference to _Dmain which didn't work when
|
||||
druntime was made into a shared library and was linked to a program, such
|
||||
as a C++ program, that didn't have a _Dmain. */
|
||||
|
||||
void
|
||||
Compiler::genCmain (Scope *sc)
|
||||
{
|
||||
static bool initialized = false;
|
||||
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
/* The D code to be generated is provided by __entrypoint.di, try to load it,
|
||||
but don't fail if unfound. */
|
||||
unsigned errors = global.startGagging ();
|
||||
Module *m = Module::load (Loc (), NULL, Identifier::idPool ("__entrypoint"));
|
||||
|
||||
if (global.endGagging (errors))
|
||||
m = NULL;
|
||||
|
||||
if (m != NULL)
|
||||
{
|
||||
m->importedFrom = m;
|
||||
m->importAll (NULL);
|
||||
dsymbolSemantic (m, NULL);
|
||||
semantic2 (m, NULL);
|
||||
semantic3 (m, NULL);
|
||||
d_add_entrypoint_module (m, sc->_module);
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/* Perform a reinterpret cast of EXPR to type TYPE for use in CTFE.
|
||||
The front end should have already ensured that EXPR is a constant,
|
||||
so we just lower the value to GCC and return the converted CST. */
|
||||
|
@ -123,7 +88,7 @@ Compiler::paintAsType (UnionExp *, Expression *expr, Type *type)
|
|||
/* Encode CST to buffer. */
|
||||
int len = native_encode_expr (cst, buffer, sizeof (buffer));
|
||||
|
||||
if (tb->ty == Tsarray)
|
||||
if (tb->ty == TY::Tsarray)
|
||||
{
|
||||
/* Interpret value as a vector of the same size,
|
||||
then return the array literal. */
|
||||
|
@ -161,22 +126,22 @@ Compiler::onParseModule (Module *m)
|
|||
{
|
||||
ModuleDeclaration *md = m->md;
|
||||
|
||||
if (!md || !md->id || !md->packages)
|
||||
if (!md || !md->id|| md->packages.length == 0)
|
||||
{
|
||||
Identifier *id = (md && md->id) ? md->id : m->ident;
|
||||
if (!strcmp (id->toChars (), "object"))
|
||||
create_tinfo_types (m);
|
||||
}
|
||||
else if (md->packages->length == 1)
|
||||
else if (md->packages.length == 1)
|
||||
{
|
||||
if (!strcmp ((*md->packages)[0]->toChars (), "gcc")
|
||||
if (!strcmp (md->packages.ptr[0]->toChars (), "gcc")
|
||||
&& !strcmp (md->id->toChars (), "builtins"))
|
||||
d_build_builtins_module (m);
|
||||
}
|
||||
else if (md->packages->length == 2)
|
||||
else if (md->packages.length == 2)
|
||||
{
|
||||
if (!strcmp ((*md->packages)[0]->toChars (), "core")
|
||||
&& !strcmp ((*md->packages)[1]->toChars (), "stdc"))
|
||||
if (!strcmp (md->packages.ptr[0]->toChars (), "core")
|
||||
&& !strcmp (md->packages.ptr[1]->toChars (), "stdc"))
|
||||
d_add_builtin_module (m);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -361,14 +361,14 @@ convert_expr (tree exp, Type *etype, Type *totype)
|
|||
|
||||
switch (ebtype->ty)
|
||||
{
|
||||
case Tdelegate:
|
||||
if (tbtype->ty == Tdelegate)
|
||||
case TY::Tdelegate:
|
||||
if (tbtype->ty == TY::Tdelegate)
|
||||
{
|
||||
exp = d_save_expr (exp);
|
||||
return build_delegate_cst (delegate_method (exp),
|
||||
delegate_object (exp), totype);
|
||||
}
|
||||
else if (tbtype->ty == Tpointer)
|
||||
else if (tbtype->ty == TY::Tpointer)
|
||||
{
|
||||
/* The front-end converts <delegate>.ptr to cast (void *)<delegate>.
|
||||
Maybe should only allow void* ? */
|
||||
|
@ -382,8 +382,8 @@ convert_expr (tree exp, Type *etype, Type *totype)
|
|||
}
|
||||
break;
|
||||
|
||||
case Tstruct:
|
||||
if (tbtype->ty == Tstruct)
|
||||
case TY::Tstruct:
|
||||
if (tbtype->ty == TY::Tstruct)
|
||||
{
|
||||
if (totype->size () == etype->size ())
|
||||
{
|
||||
|
@ -400,8 +400,8 @@ convert_expr (tree exp, Type *etype, Type *totype)
|
|||
/* else, default conversion, which should produce an error. */
|
||||
break;
|
||||
|
||||
case Tclass:
|
||||
if (tbtype->ty == Tclass)
|
||||
case TY::Tclass:
|
||||
if (tbtype->ty == TY::Tclass)
|
||||
{
|
||||
ClassDeclaration *cdfrom = ebtype->isClassHandle ();
|
||||
ClassDeclaration *cdto = tbtype->isClassHandle ();
|
||||
|
@ -460,12 +460,12 @@ convert_expr (tree exp, Type *etype, Type *totype)
|
|||
/* else default conversion. */
|
||||
break;
|
||||
|
||||
case Tsarray:
|
||||
if (tbtype->ty == Tpointer)
|
||||
case TY::Tsarray:
|
||||
if (tbtype->ty == TY::Tpointer)
|
||||
{
|
||||
result = build_nop (build_ctype (totype), build_address (exp));
|
||||
}
|
||||
else if (tbtype->ty == Tarray)
|
||||
else if (tbtype->ty == TY::Tarray)
|
||||
{
|
||||
dinteger_t dim = ebtype->isTypeSArray ()->dim->toInteger ();
|
||||
dinteger_t esize = ebtype->nextOf ()->size ();
|
||||
|
@ -490,12 +490,12 @@ convert_expr (tree exp, Type *etype, Type *totype)
|
|||
return d_array_value (build_ctype (totype), size_int (dim),
|
||||
build_nop (ptrtype, build_address (exp)));
|
||||
}
|
||||
else if (tbtype->ty == Tsarray)
|
||||
else if (tbtype->ty == TY::Tsarray)
|
||||
{
|
||||
/* D allows casting a static array to any static array type. */
|
||||
return build_nop (build_ctype (totype), exp);
|
||||
}
|
||||
else if (tbtype->ty == Tstruct)
|
||||
else if (tbtype->ty == TY::Tstruct)
|
||||
{
|
||||
/* And allows casting a static array to any struct type too.
|
||||
Type sizes should have already been checked by the frontend. */
|
||||
|
@ -510,12 +510,12 @@ convert_expr (tree exp, Type *etype, Type *totype)
|
|||
}
|
||||
break;
|
||||
|
||||
case Tarray:
|
||||
if (tbtype->ty == Tpointer)
|
||||
case TY::Tarray:
|
||||
if (tbtype->ty == TY::Tpointer)
|
||||
{
|
||||
return d_convert (build_ctype (totype), d_array_ptr (exp));
|
||||
}
|
||||
else if (tbtype->ty == Tarray)
|
||||
else if (tbtype->ty == TY::Tarray)
|
||||
{
|
||||
/* Assume tvoid->size() == 1. */
|
||||
d_uns64 fsize = ebtype->nextOf ()->toBasetype ()->size ();
|
||||
|
@ -523,9 +523,18 @@ convert_expr (tree exp, Type *etype, Type *totype)
|
|||
|
||||
if (fsize != tsize)
|
||||
{
|
||||
/* Conversion requires a reinterpret cast of array. */
|
||||
return build_libcall (LIBCALL_ARRAYCAST, totype, 3,
|
||||
size_int (tsize), size_int (fsize), exp);
|
||||
/* Conversion requires a reinterpret cast of array.
|
||||
This case should have been lowered in the semantic pass. */
|
||||
if (tsize != 0 && fsize % tsize == 0)
|
||||
{
|
||||
/* Set array dimension to (length * (fsize / tsize)). */
|
||||
tree newlength = size_mult_expr (d_array_length (exp),
|
||||
size_int (fsize / tsize));
|
||||
return d_array_value (build_ctype (totype), newlength,
|
||||
d_array_ptr (exp));
|
||||
}
|
||||
else
|
||||
gcc_unreachable ();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -534,7 +543,7 @@ convert_expr (tree exp, Type *etype, Type *totype)
|
|||
return build_vconvert (build_ctype (totype), exp);
|
||||
}
|
||||
}
|
||||
else if (tbtype->ty == Tsarray)
|
||||
else if (tbtype->ty == TY::Tsarray)
|
||||
{
|
||||
/* Strings are treated as dynamic arrays in D2. */
|
||||
if (ebtype->isString () && tbtype->isString ())
|
||||
|
@ -548,23 +557,23 @@ convert_expr (tree exp, Type *etype, Type *totype)
|
|||
}
|
||||
break;
|
||||
|
||||
case Taarray:
|
||||
if (tbtype->ty == Taarray)
|
||||
case TY::Taarray:
|
||||
if (tbtype->ty == TY::Taarray)
|
||||
return build_vconvert (build_ctype (totype), exp);
|
||||
/* Can convert associative arrays to void pointers. */
|
||||
else if (tbtype->ty == Tpointer && tbtype->nextOf ()->ty == Tvoid)
|
||||
else if (tbtype->ty == TY::Tpointer && tbtype->nextOf ()->ty == TY::Tvoid)
|
||||
return build_vconvert (build_ctype (totype), exp);
|
||||
/* Else, default conversion, which should product an error. */
|
||||
break;
|
||||
|
||||
case Tpointer:
|
||||
case TY::Tpointer:
|
||||
/* Can convert void pointers to associative arrays too. */
|
||||
if (tbtype->ty == Taarray && ebtype->nextOf ()->ty == Tvoid)
|
||||
if (tbtype->ty == TY::Taarray && ebtype->nextOf ()->ty == TY::Tvoid)
|
||||
return build_vconvert (build_ctype (totype), exp);
|
||||
break;
|
||||
|
||||
case Tnull:
|
||||
case Tnoreturn:
|
||||
case TY::Tnull:
|
||||
case TY::Tnoreturn:
|
||||
/* Casting from `typeof(null)' for `null' expressions, or `typeof(*null)'
|
||||
for `noreturn' expressions is represented as all zeros. */
|
||||
result = build_typeof_null_value (totype);
|
||||
|
@ -574,8 +583,8 @@ convert_expr (tree exp, Type *etype, Type *totype)
|
|||
result = compound_expr (exp, result);
|
||||
break;
|
||||
|
||||
case Tvector:
|
||||
if (tbtype->ty == Tsarray)
|
||||
case TY::Tvector:
|
||||
if (tbtype->ty == TY::Tsarray)
|
||||
{
|
||||
if (tbtype->size () == ebtype->size ())
|
||||
return build_vconvert (build_ctype (totype), exp);
|
||||
|
@ -613,7 +622,7 @@ convert_for_rvalue (tree expr, Type *etype, Type *totype)
|
|||
Type *ebtype = etype->toBasetype ();
|
||||
Type *tbtype = totype->toBasetype ();
|
||||
|
||||
if (ebtype->ty == Tbool)
|
||||
if (ebtype->ty == TY::Tbool)
|
||||
{
|
||||
/* If casting from bool, the result is either 0 or 1, any other value
|
||||
violates @safe code, so enforce that it is never invalid. */
|
||||
|
@ -651,7 +660,7 @@ convert_for_assignment (tree expr, Type *etype, Type *totype)
|
|||
|
||||
/* Assuming this only has to handle converting a non Tsarray type to
|
||||
arbitrarily dimensioned Tsarrays. */
|
||||
if (tbtype->ty == Tsarray)
|
||||
if (tbtype->ty == TY::Tsarray)
|
||||
{
|
||||
Type *telem = tbtype->nextOf ()->baseElemOf ();
|
||||
|
||||
|
@ -685,7 +694,7 @@ convert_for_assignment (tree expr, Type *etype, Type *totype)
|
|||
}
|
||||
|
||||
/* D Front end uses IntegerExp(0) to mean zero-init an array or structure. */
|
||||
if ((tbtype->ty == Tsarray || tbtype->ty == Tstruct)
|
||||
if ((tbtype->ty == TY::Tsarray || tbtype->ty == TY::Tstruct)
|
||||
&& ebtype->isintegral ())
|
||||
{
|
||||
if (!integer_zerop (expr))
|
||||
|
@ -736,12 +745,12 @@ convert_for_condition (tree expr, Type *type)
|
|||
|
||||
switch (type->toBasetype ()->ty)
|
||||
{
|
||||
case Taarray:
|
||||
case TY::Taarray:
|
||||
/* Checks that aa.ptr !is null. */
|
||||
result = component_ref (expr, TYPE_FIELDS (TREE_TYPE (expr)));
|
||||
break;
|
||||
|
||||
case Tarray:
|
||||
case TY::Tarray:
|
||||
{
|
||||
/* Checks (arr.length || arr.ptr) (i.e arr !is null). */
|
||||
expr = d_save_expr (expr);
|
||||
|
@ -762,7 +771,7 @@ convert_for_condition (tree expr, Type *type)
|
|||
break;
|
||||
}
|
||||
|
||||
case Tdelegate:
|
||||
case TY::Tdelegate:
|
||||
{
|
||||
/* Checks (function || object), but what good is it if there is
|
||||
a null function pointer? */
|
||||
|
@ -783,7 +792,7 @@ convert_for_condition (tree expr, Type *type)
|
|||
break;
|
||||
}
|
||||
|
||||
case Tnoreturn:
|
||||
case TY::Tnoreturn:
|
||||
/* Front-end allows conditionals that never return, represent the
|
||||
conditional result value as all zeros. */
|
||||
result = build_zero_cst (d_bool_type);
|
||||
|
@ -810,10 +819,10 @@ d_array_convert (Expression *exp)
|
|||
{
|
||||
Type *tb = exp->type->toBasetype ();
|
||||
|
||||
if (tb->ty == Tarray)
|
||||
if (tb->ty == TY::Tarray)
|
||||
return build_expr (exp);
|
||||
|
||||
if (tb->ty == Tsarray)
|
||||
if (tb->ty == TY::Tsarray)
|
||||
{
|
||||
Type *totype = tb->nextOf ()->arrayOf ();
|
||||
return convert_expr (build_expr (exp), exp->type, totype);
|
||||
|
@ -832,7 +841,8 @@ d_array_convert (Type *etype, Expression *exp)
|
|||
{
|
||||
Type *tb = exp->type->toBasetype ();
|
||||
|
||||
if ((tb->ty != Tarray && tb->ty != Tsarray) || same_type_p (tb, etype))
|
||||
if ((tb->ty != TY::Tarray && tb->ty != TY::Tsarray)
|
||||
|| same_type_p (tb, etype))
|
||||
{
|
||||
/* Convert single element to an array. */
|
||||
tree expr = build_expr (exp);
|
||||
|
|
|
@ -222,15 +222,6 @@ d_diagnostic_report_diagnostic (const Loc &loc, int opt, const char *format,
|
|||
message prefix PREFIX1 and PREFIX2, increasing the global or gagged
|
||||
error count. */
|
||||
|
||||
void ATTRIBUTE_GCC_DIAG(2,3)
|
||||
error (const Loc &loc, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
verror (loc, format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
void ATTRIBUTE_GCC_DIAG(2,0)
|
||||
verror (const Loc &loc, const char *format, va_list ap,
|
||||
const char *prefix1, const char *prefix2, const char *)
|
||||
|
@ -263,15 +254,6 @@ verror (const Loc &loc, const char *format, va_list ap,
|
|||
/* Print supplementary message about the last error with explicit location LOC.
|
||||
This doesn't increase the global error count. */
|
||||
|
||||
void ATTRIBUTE_GCC_DIAG(2,3)
|
||||
errorSupplemental (const Loc &loc, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
verrorSupplemental (loc, format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
void ATTRIBUTE_GCC_DIAG(2,0)
|
||||
verrorSupplemental (const Loc &loc, const char *format, va_list ap)
|
||||
{
|
||||
|
@ -284,15 +266,6 @@ verrorSupplemental (const Loc &loc, const char *format, va_list ap)
|
|||
/* Print a warning message with explicit location LOC, increasing the
|
||||
global warning count. */
|
||||
|
||||
void ATTRIBUTE_GCC_DIAG(2,3)
|
||||
warning (const Loc &loc, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
vwarning (loc, format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
void ATTRIBUTE_GCC_DIAG(2,0)
|
||||
vwarning (const Loc &loc, const char *format, va_list ap)
|
||||
{
|
||||
|
@ -311,15 +284,6 @@ vwarning (const Loc &loc, const char *format, va_list ap)
|
|||
/* Print supplementary message about the last warning with explicit location
|
||||
LOC. This doesn't increase the global warning count. */
|
||||
|
||||
void ATTRIBUTE_GCC_DIAG(2,3)
|
||||
warningSupplemental (const Loc &loc, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
vwarningSupplemental (loc, format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
void ATTRIBUTE_GCC_DIAG(2,0)
|
||||
vwarningSupplemental (const Loc &loc, const char *format, va_list ap)
|
||||
{
|
||||
|
@ -333,15 +297,6 @@ vwarningSupplemental (const Loc &loc, const char *format, va_list ap)
|
|||
message prefix PREFIX1 and PREFIX2, increasing the global warning or
|
||||
error count depending on how deprecations are treated. */
|
||||
|
||||
void ATTRIBUTE_GCC_DIAG(2,3)
|
||||
deprecation (const Loc &loc, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
vdeprecation (loc, format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
void ATTRIBUTE_GCC_DIAG(2,0)
|
||||
vdeprecation (const Loc &loc, const char *format, va_list ap,
|
||||
const char *prefix1, const char *prefix2)
|
||||
|
@ -372,15 +327,6 @@ vdeprecation (const Loc &loc, const char *format, va_list ap,
|
|||
/* Print supplementary message about the last deprecation with explicit
|
||||
location LOC. This does not increase the global error count. */
|
||||
|
||||
void ATTRIBUTE_GCC_DIAG(2,3)
|
||||
deprecationSupplemental (const Loc &loc, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
vdeprecationSupplemental (loc, format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
void ATTRIBUTE_GCC_DIAG(2,0)
|
||||
vdeprecationSupplemental (const Loc &loc, const char *format, va_list ap)
|
||||
{
|
||||
|
@ -392,30 +338,19 @@ vdeprecationSupplemental (const Loc &loc, const char *format, va_list ap)
|
|||
|
||||
/* Print a verbose message with explicit location LOC. */
|
||||
|
||||
void ATTRIBUTE_GCC_DIAG(2, 3)
|
||||
message (const Loc &loc, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
vmessage (loc, format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
void ATTRIBUTE_GCC_DIAG(2,0)
|
||||
vmessage (const Loc &loc, const char *format, va_list ap)
|
||||
{
|
||||
d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, true);
|
||||
}
|
||||
|
||||
/* Same as above, but doesn't take a location argument. */
|
||||
/* Print a tip message with prefix and highlighing. */
|
||||
|
||||
void ATTRIBUTE_GCC_DIAG(1, 2)
|
||||
message (const char *format, ...)
|
||||
void ATTRIBUTE_GCC_DIAG(1,0)
|
||||
vtip (const char *format, va_list ap)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
vmessage (Loc (), format, ap);
|
||||
va_end (ap);
|
||||
if (!global.gag)
|
||||
d_diagnostic_report_diagnostic (Loc (), 0, format, ap, DK_DEBUG, true);
|
||||
}
|
||||
|
||||
/* Call this after printing out fatal error messages to clean up and
|
||||
|
|
|
@ -27,116 +27,11 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "dmd/scope.h"
|
||||
|
||||
#include "tree.h"
|
||||
#include "options.h"
|
||||
#include "fold-const.h"
|
||||
#include "diagnostic.h"
|
||||
|
||||
#include "d-tree.h"
|
||||
|
||||
|
||||
/* Implements the Global interface defined by the frontend.
|
||||
Used for managing the state of the current compilation. */
|
||||
|
||||
Global global;
|
||||
|
||||
void
|
||||
Global::_init (void)
|
||||
{
|
||||
this->mars_ext = "d";
|
||||
this->hdr_ext = "di";
|
||||
this->doc_ext = "html";
|
||||
this->ddoc_ext = "ddoc";
|
||||
this->json_ext = "json";
|
||||
this->obj_ext = "o";
|
||||
|
||||
this->run_noext = true;
|
||||
this->version = "v"
|
||||
#include "verstr.h"
|
||||
;
|
||||
|
||||
this->stdmsg = stderr;
|
||||
}
|
||||
|
||||
/* Start gagging. Return the current number of gagged errors. */
|
||||
|
||||
unsigned
|
||||
Global::startGagging (void)
|
||||
{
|
||||
this->gag++;
|
||||
return this->gaggedErrors;
|
||||
}
|
||||
|
||||
/* End gagging, restoring the old gagged state. Return true if errors
|
||||
occured while gagged. */
|
||||
|
||||
bool
|
||||
Global::endGagging (unsigned oldGagged)
|
||||
{
|
||||
bool anyErrs = (this->gaggedErrors != oldGagged);
|
||||
this->gag--;
|
||||
|
||||
/* Restore the original state of gagged errors; set total errors
|
||||
to be original errors + new ungagged errors. */
|
||||
this->errors -= (this->gaggedErrors - oldGagged);
|
||||
this->gaggedErrors = oldGagged;
|
||||
|
||||
return anyErrs;
|
||||
}
|
||||
|
||||
/* Increment the error count to record that an error has occured in the
|
||||
current context. An error message may or may not have been printed. */
|
||||
|
||||
void
|
||||
Global::increaseErrorCount (void)
|
||||
{
|
||||
if (gag)
|
||||
this->gaggedErrors++;
|
||||
|
||||
this->errors++;
|
||||
}
|
||||
|
||||
|
||||
/* Implements the Loc interface defined by the frontend.
|
||||
Used for keeping track of current file/line position in code. */
|
||||
|
||||
Loc::Loc (const char *filename, unsigned linnum, unsigned charnum)
|
||||
{
|
||||
this->linnum = linnum;
|
||||
this->charnum = charnum;
|
||||
this->filename = filename;
|
||||
}
|
||||
|
||||
const char *
|
||||
Loc::toChars (void) const
|
||||
{
|
||||
OutBuffer buf;
|
||||
|
||||
if (this->filename)
|
||||
buf.printf ("%s", this->filename);
|
||||
|
||||
if (this->linnum)
|
||||
{
|
||||
buf.printf (":%u", this->linnum);
|
||||
if (this->charnum)
|
||||
buf.printf (":%u", this->charnum);
|
||||
}
|
||||
|
||||
return buf.extractChars ();
|
||||
}
|
||||
|
||||
bool
|
||||
Loc::equals (const Loc &loc)
|
||||
{
|
||||
if (this->linnum != loc.linnum || this->charnum != loc.charnum)
|
||||
return false;
|
||||
|
||||
if (!FileName::equals (this->filename, loc.filename))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Implements back-end specific interfaces used by the frontend. */
|
||||
|
||||
/* Determine if function FD is a builtin one that we can evaluate in CTFE. */
|
||||
|
@ -144,7 +39,7 @@ Loc::equals (const Loc &loc)
|
|||
BUILTIN
|
||||
isBuiltin (FuncDeclaration *fd)
|
||||
{
|
||||
if (fd->builtin != BUILTINunknown)
|
||||
if (fd->builtin != BUILTIN::unknown)
|
||||
return fd->builtin;
|
||||
|
||||
maybe_set_intrinsic (fd);
|
||||
|
@ -158,7 +53,7 @@ isBuiltin (FuncDeclaration *fd)
|
|||
Expression *
|
||||
eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments)
|
||||
{
|
||||
if (fd->builtin == BUILTINunimp)
|
||||
if (fd->builtin == BUILTIN::unimp)
|
||||
return NULL;
|
||||
|
||||
tree decl = get_symbol_decl (fd);
|
||||
|
@ -185,16 +80,8 @@ eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments)
|
|||
Type *
|
||||
getTypeInfoType (Loc loc, Type *type, Scope *sc)
|
||||
{
|
||||
gcc_assert (type->ty != Terror);
|
||||
gcc_assert (type->ty != TY::Terror);
|
||||
check_typeinfo_type (loc, sc);
|
||||
create_typeinfo (type, sc ? sc->_module->importedFrom : NULL);
|
||||
return type->vtinfo->type;
|
||||
}
|
||||
|
||||
/* Return an inlined copy of a default argument for a function parameter. */
|
||||
|
||||
Expression *
|
||||
inlineCopy (Expression *e, Scope *)
|
||||
{
|
||||
return e->copy ();
|
||||
}
|
||||
|
|
37
gcc/d/d-frontend.h
Normal file
37
gcc/d/d-frontend.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* d-frontend.h -- D frontend interface to the gcc back-end.
|
||||
Copyright (C) 2019 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/>. */
|
||||
|
||||
#ifndef GCC_D_FRONTEND_H
|
||||
#define GCC_D_FRONTEND_H
|
||||
|
||||
/* These functions are defined in D runtime. */
|
||||
extern "C" int rt_init (void);
|
||||
extern "C" int rt_term (void);
|
||||
//extern "C" void gc_disable (void);
|
||||
extern "C" void *gc_malloc (size_t sz, unsigned ba = 0, const void *ti = NULL);
|
||||
extern "C" void gc_free (void *);
|
||||
extern "C" void gc_collect (void);
|
||||
|
||||
template<typename T>
|
||||
inline T *
|
||||
d_gc_malloc (void)
|
||||
{
|
||||
void *ptr = gc_malloc (sizeof (T));
|
||||
return new(ptr) T ();
|
||||
}
|
||||
|
||||
#endif
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "coretypes.h"
|
||||
|
||||
#include "dmd/globals.h"
|
||||
#include "d-frontend.h"
|
||||
|
||||
#include "cppdefault.h"
|
||||
|
||||
|
@ -71,7 +72,7 @@ add_globalpaths (Strings *paths)
|
|||
if (paths)
|
||||
{
|
||||
if (!global.path)
|
||||
global.path = new Strings ();
|
||||
global.path = d_gc_malloc<Strings> ();
|
||||
|
||||
for (size_t i = 0; i < paths->length; i++)
|
||||
{
|
||||
|
@ -98,7 +99,7 @@ add_filepaths (Strings *paths)
|
|||
if (paths)
|
||||
{
|
||||
if (!global.filePath)
|
||||
global.filePath = new Strings ();
|
||||
global.filePath = d_gc_malloc<Strings> ();
|
||||
|
||||
for (size_t i = 0; i < paths->length; i++)
|
||||
{
|
||||
|
|
287
gcc/d/d-lang.cc
287
gcc/d/d-lang.cc
|
@ -26,12 +26,13 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "dmd/errors.h"
|
||||
#include "dmd/expression.h"
|
||||
#include "dmd/hdrgen.h"
|
||||
#include "dmd/id.h"
|
||||
#include "dmd/identifier.h"
|
||||
#include "dmd/json.h"
|
||||
#include "dmd/mangle.h"
|
||||
#include "dmd/mars.h"
|
||||
#include "dmd/module.h"
|
||||
#include "dmd/mtype.h"
|
||||
#include "dmd/root/file.h"
|
||||
#include "dmd/target.h"
|
||||
|
||||
#include "opts.h"
|
||||
|
@ -53,7 +54,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "input.h"
|
||||
|
||||
#include "d-tree.h"
|
||||
#include "id.h"
|
||||
#include "d-frontend.h"
|
||||
|
||||
|
||||
/* Array of D frontend type/decl nodes. */
|
||||
|
@ -83,10 +84,6 @@ d_option;
|
|||
/* List of modules being compiled. */
|
||||
static Modules builtin_modules;
|
||||
|
||||
/* Module where `C main' is defined, compiled in if needed. */
|
||||
static Module *entrypoint_module = NULL;
|
||||
static Module *entrypoint_root_module = NULL;
|
||||
|
||||
/* The current and global binding level in effect. */
|
||||
struct binding_level *current_binding_level;
|
||||
struct binding_level *global_binding_level;
|
||||
|
@ -202,7 +199,7 @@ deps_write (Module *module, obstack *buffer)
|
|||
deps_write_string (d_option.deps_target[i], buffer, column);
|
||||
}
|
||||
else
|
||||
deps_write_string (module->objfile->name->str, buffer, column);
|
||||
deps_write_string (module->objfile.toChars (), buffer, column);
|
||||
|
||||
obstack_1grow (buffer, ':');
|
||||
column++;
|
||||
|
@ -212,7 +209,7 @@ deps_write (Module *module, obstack *buffer)
|
|||
{
|
||||
Module *depmod = modlist.pop ();
|
||||
|
||||
const char *modstr = depmod->srcfile->name->str;
|
||||
const char *modstr = depmod->srcfile.toChars ();
|
||||
|
||||
/* Skip modules that have already been looked at. */
|
||||
if (seen_modules.add (modstr))
|
||||
|
@ -238,9 +235,7 @@ deps_write (Module *module, obstack *buffer)
|
|||
Module *m = depmod->aimports[i];
|
||||
|
||||
/* Ignore compiler-generated modules. */
|
||||
if ((m->ident == Identifier::idPool ("__entrypoint")
|
||||
|| m->ident == Identifier::idPool ("__main"))
|
||||
&& m->parent == NULL)
|
||||
if (m->ident == Identifier::idPool ("__main") && m->parent == NULL)
|
||||
continue;
|
||||
|
||||
/* Don't search system installed modules, this includes
|
||||
|
@ -251,9 +246,9 @@ deps_write (Module *module, obstack *buffer)
|
|||
&& m->parent == NULL)
|
||||
continue;
|
||||
|
||||
if (m->md && m->md->packages)
|
||||
if (m->md && m->md->packages.length)
|
||||
{
|
||||
Identifier *package = (*m->md->packages)[0];
|
||||
Identifier *package = m->md->packages.ptr[0];
|
||||
|
||||
if (package == Identifier::idPool ("core")
|
||||
|| package == Identifier::idPool ("std")
|
||||
|
@ -291,27 +286,15 @@ deps_write (Module *module, obstack *buffer)
|
|||
static void
|
||||
d_init_options (unsigned int, cl_decoded_option *decoded_options)
|
||||
{
|
||||
/* Initialize the D runtime. */
|
||||
rt_init ();
|
||||
// gc_disable ();
|
||||
|
||||
/* Set default values. */
|
||||
global._init ();
|
||||
|
||||
global.vendor = lang_hooks.name;
|
||||
global.params.argv0 = xstrdup (decoded_options[0].arg);
|
||||
global.params.link = true;
|
||||
global.params.useAssert = CHECKENABLEdefault;
|
||||
global.params.useInvariants = CHECKENABLEdefault;
|
||||
global.params.useIn = CHECKENABLEdefault;
|
||||
global.params.useOut = CHECKENABLEdefault;
|
||||
global.params.useArrayBounds = CHECKENABLEdefault;
|
||||
global.params.useSwitchError = CHECKENABLEdefault;
|
||||
global.params.checkAction = CHECKACTION_D;
|
||||
global.params.useModuleInfo = true;
|
||||
global.params.useTypeInfo = true;
|
||||
global.params.useExceptions = true;
|
||||
global.params.useInline = false;
|
||||
global.params.obj = true;
|
||||
global.params.hdrStripPlainFunctions = true;
|
||||
global.params.betterC = false;
|
||||
global.params.allInst = false;
|
||||
global.params.errorLimit = flag_max_errors;
|
||||
|
||||
/* Default extern(C++) mangling to C++14. */
|
||||
|
@ -320,9 +303,10 @@ d_init_options (unsigned int, cl_decoded_option *decoded_options)
|
|||
/* Warnings and deprecations are disabled by default. */
|
||||
global.params.useDeprecated = DIAGNOSTICinform;
|
||||
global.params.warnings = DIAGNOSTICoff;
|
||||
global.params.messageStyle = MESSAGESTYLEgnu;
|
||||
|
||||
global.params.imppath = new Strings ();
|
||||
global.params.fileImppath = new Strings ();
|
||||
global.params.imppath = d_gc_malloc<Strings> ();
|
||||
global.params.fileImppath = d_gc_malloc<Strings> ();
|
||||
|
||||
/* Extra GDC-specific options. */
|
||||
d_option.fonly = NULL;
|
||||
|
@ -462,6 +446,11 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
|
|||
: (value == 1) ? CHECKENABLEsafeonly : CHECKENABLEoff;
|
||||
break;
|
||||
|
||||
case OPT_fcheckaction_:
|
||||
global.params.checkAction = (value == 0) ? CHECKACTION_D
|
||||
: (value == 1) ? CHECKACTION_halt : CHECKACTION_context;
|
||||
break;
|
||||
|
||||
case OPT_fdebug:
|
||||
global.params.debuglevel = value ? 1 : 0;
|
||||
break;
|
||||
|
@ -480,7 +469,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
|
|||
if (Identifier::isValidIdentifier (CONST_CAST (char *, arg)))
|
||||
{
|
||||
if (!global.params.debugids)
|
||||
global.params.debugids = new Strings ();
|
||||
global.params.debugids = d_gc_malloc<Strings> ();
|
||||
global.params.debugids->push (arg);
|
||||
break;
|
||||
}
|
||||
|
@ -510,6 +499,16 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
|
|||
global.params.betterC = !value;
|
||||
break;
|
||||
|
||||
case OPT_fdump_c___spec_:
|
||||
if (global.params.doCxxHdrGeneration == CxxHeaderMode::none)
|
||||
global.params.doCxxHdrGeneration = CxxHeaderMode::silent;
|
||||
global.params.cxxhdrname = arg;
|
||||
break;
|
||||
|
||||
case OPT_fdump_c___spec_verbose:
|
||||
global.params.doCxxHdrGeneration = CxxHeaderMode::verbose;
|
||||
break;
|
||||
|
||||
case OPT_fdump_d_original:
|
||||
global.params.vcg_ast = value;
|
||||
break;
|
||||
|
@ -518,6 +517,22 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
|
|||
global.params.useExceptions = value;
|
||||
break;
|
||||
|
||||
case OPT_fextern_std_:
|
||||
switch (value)
|
||||
{
|
||||
case CppStdRevisionCpp98:
|
||||
case CppStdRevisionCpp11:
|
||||
case CppStdRevisionCpp14:
|
||||
case CppStdRevisionCpp17:
|
||||
case CppStdRevisionCpp20:
|
||||
global.params.cplusplus = (CppStdRevision) value;
|
||||
break;
|
||||
|
||||
default:
|
||||
error ("bad argument for %<-fextern-std%>: %qs", arg);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPT_fignore_unknown_pragmas:
|
||||
global.params.ignoreUnsupportedPragmas = value;
|
||||
break;
|
||||
|
@ -552,35 +567,115 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
|
|||
global.params.useIn = value ? CHECKENABLEon : CHECKENABLEoff;
|
||||
break;
|
||||
|
||||
case OPT_fpreview_all:
|
||||
global.params.ehnogc = value;
|
||||
global.params.useDIP25 = FeatureState::enabled;
|
||||
global.params.useDIP1000 = FeatureState::enabled;
|
||||
global.params.useDIP1021 = value;
|
||||
global.params.dtorFields = FeatureState::enabled;
|
||||
global.params.fieldwise = value;
|
||||
global.params.fixAliasThis = value;
|
||||
global.params.previewIn = value;
|
||||
global.params.fix16997 = value;
|
||||
global.params.markdown = value;
|
||||
global.params.noSharedAccess = value;
|
||||
global.params.rvalueRefParam = value;
|
||||
global.params.inclusiveInContracts = value;
|
||||
global.params.shortenedMethods = value;
|
||||
break;
|
||||
|
||||
case OPT_fpreview_dip1000:
|
||||
global.params.useDIP1000 = FeatureState::enabled;
|
||||
break;
|
||||
|
||||
case OPT_fpreview_dip1008:
|
||||
global.params.ehnogc = value;
|
||||
break;
|
||||
|
||||
case OPT_fpreview_dip1021:
|
||||
global.params.useDIP1021 = value;
|
||||
break;
|
||||
|
||||
case OPT_fpreview_dip25:
|
||||
global.params.useDIP25 = FeatureState::enabled;
|
||||
break;
|
||||
|
||||
case OPT_fpreview_dtorfields:
|
||||
global.params.dtorFields = FeatureState::enabled;
|
||||
break;
|
||||
|
||||
case OPT_fpreview_fieldwise:
|
||||
global.params.fieldwise = value;
|
||||
break;
|
||||
|
||||
case OPT_fpreview_fixaliasthis:
|
||||
global.params.fixAliasThis = value;
|
||||
break;
|
||||
|
||||
case OPT_fpreview_in:
|
||||
global.params.previewIn = value;
|
||||
break;
|
||||
|
||||
case OPT_fpreview_inclusiveincontracts:
|
||||
global.params.inclusiveInContracts = value;
|
||||
break;
|
||||
|
||||
case OPT_fpreview_intpromote:
|
||||
global.params.fix16997 = value;
|
||||
break;
|
||||
|
||||
case OPT_fpreview_nosharedaccess:
|
||||
global.params.noSharedAccess = value;
|
||||
break;
|
||||
|
||||
case OPT_fpreview_rvaluerefparam:
|
||||
global.params.rvalueRefParam = value;
|
||||
break;
|
||||
|
||||
case OPT_fpreview_shortenedmethods:
|
||||
global.params.shortenedMethods = value;
|
||||
break;
|
||||
|
||||
case OPT_frelease:
|
||||
global.params.release = value;
|
||||
break;
|
||||
|
||||
case OPT_frevert_all:
|
||||
global.params.useDIP25 = FeatureState::disabled;
|
||||
global.params.markdown = !value;
|
||||
global.params.dtorFields = FeatureState::disabled;
|
||||
break;
|
||||
|
||||
case OPT_frevert_dip25:
|
||||
global.params.useDIP25 = FeatureState::disabled;
|
||||
break;
|
||||
|
||||
case OPT_frevert_dtorfields:
|
||||
global.params.dtorFields = FeatureState::disabled;
|
||||
break;
|
||||
|
||||
case OPT_frevert_markdown:
|
||||
global.params.markdown = !value;
|
||||
break;
|
||||
|
||||
case OPT_frtti:
|
||||
global.params.useTypeInfo = value;
|
||||
break;
|
||||
|
||||
case OPT_fsave_mixins_:
|
||||
global.params.mixinFile = arg;
|
||||
global.params.mixinOut = d_gc_malloc<OutBuffer> ();
|
||||
break;
|
||||
|
||||
case OPT_fswitch_errors:
|
||||
global.params.useSwitchError = value ? CHECKENABLEon : CHECKENABLEoff;
|
||||
break;
|
||||
|
||||
case OPT_ftransition_all:
|
||||
global.params.vtls = value;
|
||||
global.params.vfield = value;
|
||||
global.params.vcomplex = value;
|
||||
break;
|
||||
|
||||
case OPT_ftransition_complex:
|
||||
global.params.vcomplex = value;
|
||||
break;
|
||||
|
||||
case OPT_ftransition_dip1000:
|
||||
global.params.vsafe = value;
|
||||
global.params.useDIP25 = value;
|
||||
break;
|
||||
|
||||
case OPT_ftransition_dip25:
|
||||
global.params.useDIP25 = value;
|
||||
global.params.vgc = value;
|
||||
global.params.vmarkdown= value;
|
||||
global.params.vtls = value;
|
||||
break;
|
||||
|
||||
case OPT_ftransition_field:
|
||||
|
@ -591,6 +686,14 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
|
|||
global.params.vgc = value;
|
||||
break;
|
||||
|
||||
case OPT_ftransition_vmarkdown:
|
||||
global.params.vmarkdown = value;
|
||||
break;
|
||||
|
||||
case OPT_ftransition_templates:
|
||||
global.params.vtemplates = value;
|
||||
break;
|
||||
|
||||
case OPT_ftransition_tls:
|
||||
global.params.vtls = value;
|
||||
break;
|
||||
|
@ -613,7 +716,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
|
|||
if (Identifier::isValidIdentifier (CONST_CAST (char *, arg)))
|
||||
{
|
||||
if (!global.params.versionids)
|
||||
global.params.versionids = new Strings ();
|
||||
global.params.versionids = d_gc_malloc<Strings> ();
|
||||
global.params.versionids->push (arg);
|
||||
break;
|
||||
}
|
||||
|
@ -804,6 +907,14 @@ d_post_options (const char ** fn)
|
|||
global.params.checkAction = CHECKACTION_C;
|
||||
}
|
||||
|
||||
/* Enabling DIP1021 implies DIP1000. */
|
||||
if (global.params.useDIP1021)
|
||||
global.params.useDIP1000 = FeatureState::enabled;
|
||||
|
||||
/* Enabling DIP1000 implies DIP25. */
|
||||
if (global.params.useDIP1000 == FeatureState::enabled)
|
||||
global.params.useDIP25 = FeatureState::enabled;
|
||||
|
||||
/* Keep in sync with existing -fbounds-check flag. */
|
||||
flag_bounds_check = (global.params.useArrayBounds == CHECKENABLEon);
|
||||
|
||||
|
@ -828,6 +939,7 @@ d_post_options (const char ** fn)
|
|||
global.params.symdebug = write_symbols != NO_DEBUG;
|
||||
global.params.useInline = flag_inline_functions;
|
||||
global.params.showColumns = flag_show_column;
|
||||
global.params.printErrorContext = flag_diagnostics_show_caret;
|
||||
|
||||
if (global.params.useInline)
|
||||
global.params.hdrStripPlainFunctions = false;
|
||||
|
@ -872,17 +984,6 @@ d_add_builtin_module (Module *m)
|
|||
builtin_modules.push (m);
|
||||
}
|
||||
|
||||
/* Record the entrypoint module ENTRY which will be compiled in the current
|
||||
compilation. ROOT is the module scope where this was requested from. */
|
||||
|
||||
void
|
||||
d_add_entrypoint_module (Module *entry, Module *root)
|
||||
{
|
||||
/* We are emitting this straight to object file. */
|
||||
entrypoint_module = entry;
|
||||
entrypoint_root_module = root;
|
||||
}
|
||||
|
||||
/* Implements the lang_hooks.parse_file routine for language D. */
|
||||
|
||||
static void
|
||||
|
@ -891,7 +992,7 @@ d_parse_file (void)
|
|||
if (global.params.verbose)
|
||||
{
|
||||
message ("binary %s", global.params.argv0.ptr);
|
||||
message ("version %s", global.version.ptr);
|
||||
message ("version %s", global.versionChars ());
|
||||
|
||||
if (global.versionids)
|
||||
{
|
||||
|
@ -955,16 +1056,16 @@ d_parse_file (void)
|
|||
|
||||
/* Handling stdin, generate a unique name for the module. */
|
||||
Module *m = Module::create (in_fnames[i],
|
||||
Identifier::generateId ("__stdin"),
|
||||
Identifier::idPool ("__stdin"),
|
||||
global.params.doDocComments,
|
||||
global.params.doHdrGeneration);
|
||||
modules.push (m);
|
||||
|
||||
/* Overwrite the source file for the module, the one created by
|
||||
Module::create would have a forced a `.d' suffix. */
|
||||
m->srcfile = File::create ("<stdin>");
|
||||
m->srcfile->len = len;
|
||||
m->srcfile->buffer = buffer;
|
||||
m->srcBuffer = FileBuffer::create ();
|
||||
m->srcBuffer->data.length = len;
|
||||
m->srcBuffer->data.ptr = buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1011,15 +1112,16 @@ d_parse_file (void)
|
|||
}
|
||||
|
||||
/* Load the module containing D main. */
|
||||
Module *main_module = NULL;
|
||||
if (global.params.addMain)
|
||||
{
|
||||
unsigned errors = global.startGagging ();
|
||||
Module *m = Module::load (Loc (), NULL, Identifier::idPool ("__main"));
|
||||
main_module = Module::load (Loc (), NULL, Identifier::idPool ("__main"));
|
||||
|
||||
if (!global.endGagging (errors))
|
||||
{
|
||||
m->importedFrom = m;
|
||||
modules.push (m);
|
||||
main_module->importedFrom = main_module;
|
||||
modules.push (main_module);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1038,7 +1140,7 @@ d_parse_file (void)
|
|||
for (size_t i = 0; i < modules.length; i++)
|
||||
{
|
||||
Module *m = modules[i];
|
||||
if (d_option.fonly && m != Module::rootModule)
|
||||
if (m->isHdrFile || (d_option.fonly && m != Module::rootModule))
|
||||
continue;
|
||||
|
||||
if (global.params.verbose)
|
||||
|
@ -1203,7 +1305,7 @@ d_parse_file (void)
|
|||
if (name && (name[0] != '-' || name[1] != '\0'))
|
||||
{
|
||||
const char *nameext
|
||||
= FileName::defaultExt (name, global.json_ext.ptr);
|
||||
= FileName::defaultExt (name, json_ext.ptr);
|
||||
json_stream = fopen (nameext, "w");
|
||||
if (!json_stream)
|
||||
{
|
||||
|
@ -1245,22 +1347,25 @@ d_parse_file (void)
|
|||
}
|
||||
}
|
||||
|
||||
/* Generate C++ header files. */
|
||||
if (global.params.doCxxHdrGeneration != CxxHeaderMode::none)
|
||||
genCppHdrFiles (modules);
|
||||
|
||||
if (global.errors)
|
||||
goto had_errors;
|
||||
|
||||
for (size_t i = 0; i < modules.length; i++)
|
||||
{
|
||||
Module *m = modules[i];
|
||||
if (d_option.fonly && m != Module::rootModule)
|
||||
if ((m->isHdrFile && m != main_module)
|
||||
|| (d_option.fonly && m != Module::rootModule))
|
||||
continue;
|
||||
|
||||
if (global.params.verbose)
|
||||
message ("code %s", m->toChars ());
|
||||
|
||||
if (!flag_syntax_only)
|
||||
{
|
||||
if ((entrypoint_module != NULL) && (m == entrypoint_root_module))
|
||||
build_decl_tree (entrypoint_module);
|
||||
|
||||
build_decl_tree (m);
|
||||
}
|
||||
build_decl_tree (m);
|
||||
}
|
||||
|
||||
/* And end the main input file, if the debug writer wants it. */
|
||||
|
@ -1272,16 +1377,37 @@ d_parse_file (void)
|
|||
exit with an error status. */
|
||||
errorcount += (global.errors + global.warnings);
|
||||
|
||||
/* We want to write the mixin expansion file also on error. */
|
||||
if (global.params.mixinOut)
|
||||
{
|
||||
FILE *mixin_stream = fopen (global.params.mixinFile, "w");
|
||||
|
||||
if (mixin_stream)
|
||||
{
|
||||
OutBuffer *buf = global.params.mixinOut;
|
||||
fprintf (mixin_stream, "%s", buf->peekChars ());
|
||||
|
||||
if (ferror (mixin_stream) || fclose (mixin_stream))
|
||||
fatal_error (input_location, "closing mixin file %s: %m",
|
||||
global.params.mixinFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
fatal_error (input_location, "opening mixin file %s: %m",
|
||||
global.params.mixinFile);
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove generated .di files on error. */
|
||||
if (errorcount && dump_headers)
|
||||
{
|
||||
for (size_t i = 0; i < modules.length; i++)
|
||||
{
|
||||
Module *m = modules[i];
|
||||
if (d_option.fonly && m != Module::rootModule)
|
||||
if (m->isHdrFile || (d_option.fonly && m != Module::rootModule))
|
||||
continue;
|
||||
|
||||
remove (m->hdrfile->toChars ());
|
||||
remove (m->hdrfile.toChars ());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1406,7 +1532,7 @@ d_type_promotes_to (tree type)
|
|||
/* Promotions are only applied on unnamed function arguments for declarations
|
||||
with `extern(C)' or `extern(C++)' linkage. */
|
||||
if (cfun && DECL_LANG_FRONTEND (cfun->decl)
|
||||
&& DECL_LANG_FRONTEND (cfun->decl)->linkage != LINKd)
|
||||
&& DECL_LANG_FRONTEND (cfun->decl)->linkage != LINK::d)
|
||||
{
|
||||
/* In [type/integer-promotions], integer promotions are conversions of the
|
||||
following types:
|
||||
|
@ -1559,7 +1685,8 @@ d_types_compatible_p (tree x, tree y)
|
|||
return true;
|
||||
|
||||
/* Type system allows implicit conversion between. */
|
||||
if (tx->implicitConvTo (ty) || ty->implicitConvTo (tx))
|
||||
if (tx->implicitConvTo (ty) != MATCH::nomatch
|
||||
|| ty->implicitConvTo (tx) != MATCH::nomatch)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,12 +30,6 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "longdouble.h"
|
||||
|
||||
|
||||
/* Constant real values 0, 1, -1 and 0.5. */
|
||||
real_t CTFloat::zero;
|
||||
real_t CTFloat::one;
|
||||
real_t CTFloat::minusone;
|
||||
real_t CTFloat::half;
|
||||
|
||||
/* Truncate longdouble to the highest precision supported by target. */
|
||||
|
||||
longdouble
|
||||
|
|
|
@ -26,60 +26,8 @@
|
|||
#endif
|
||||
#include "system.h"
|
||||
|
||||
/* Used by the dmd front-end to determine if we have POSIX-style IO. */
|
||||
#define POSIX (__linux__ || __GLIBC__ || __gnu_hurd__ || __APPLE__ \
|
||||
|| __FreeBSD__ || __NetBSD__ || __OpenBSD__ || __DragonFly__ \
|
||||
|| __sun || __unix__)
|
||||
|
||||
/* Forward assert invariants to gcc_assert. */
|
||||
#undef assert
|
||||
#define assert(EXPR) gcc_assert(EXPR)
|
||||
|
||||
/* Use libiberty's lrealpath to avoid portability problems. */
|
||||
#undef realpath
|
||||
#define realpath(a, b) lrealpath((a))
|
||||
|
||||
/* Forward ctype.h macros used by the dmd front-end to safe-ctype.h. */
|
||||
#undef isalpha
|
||||
#define isalpha(c) ISALPHA(c)
|
||||
#undef isalnum
|
||||
#define isalnum(c) ISALNUM(c)
|
||||
#undef isdigit
|
||||
#define isdigit(c) ISDIGIT(c)
|
||||
#undef islower
|
||||
#define islower(c) ISLOWER(c)
|
||||
#undef isprint
|
||||
#define isprint(c) ISPRINT(c)
|
||||
#undef isspace
|
||||
#define isspace(c) ISSPACE(c)
|
||||
#undef isupper
|
||||
#define isupper(c) ISUPPER(c)
|
||||
#undef isxdigit
|
||||
#define isxdigit(c) ISXDIGIT(c)
|
||||
#undef tolower
|
||||
#define tolower(c) TOLOWER(c)
|
||||
|
||||
/* Forward _mkdir on MinGW to mkdir in system.h. */
|
||||
#ifdef _WIN32
|
||||
#undef _mkdir
|
||||
#define _mkdir(p) mkdir(p, 0)
|
||||
#endif
|
||||
|
||||
/* Define any missing _MAX and _MIN macros. */
|
||||
#ifndef INT32_MAX
|
||||
# define INT32_MAX INTTYPE_MAXIMUM (int32_t)
|
||||
#endif
|
||||
#ifndef INT32_MIN
|
||||
# define INT32_MIN INTTYPE_MINIMUM (int32_t)
|
||||
#endif
|
||||
#ifndef INT64_MIN
|
||||
# define INT64_MIN INTTYPE_MINIMUM (int64_t)
|
||||
#endif
|
||||
#ifndef UINT32_MAX
|
||||
# define UINT32_MAX INTTYPE_MAXIMUM (uint32_t)
|
||||
#endif
|
||||
#ifndef UINT64_MAX
|
||||
# define UINT64_MAX INTTYPE_MAXIMUM (uint64_t)
|
||||
#endif
|
||||
|
||||
#endif /* GCC_D_SYSTEM_H */
|
||||
|
|
|
@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "tm.h"
|
||||
#include "tm_p.h"
|
||||
#include "target.h"
|
||||
#include "calls.h"
|
||||
|
||||
#include "d-tree.h"
|
||||
#include "d-target.h"
|
||||
|
@ -42,8 +43,6 @@ along with GCC; see the file COPYING3. If not see
|
|||
/* Implements the Target interface defined by the front end.
|
||||
Used for retrieving target-specific information. */
|
||||
|
||||
Target target;
|
||||
|
||||
/* Internal key handlers for `__traits(getTargetInfo)'. */
|
||||
static tree d_handle_target_cpp_std (void);
|
||||
static tree d_handle_target_cpp_runtime_library (void);
|
||||
|
@ -89,9 +88,6 @@ define_float_constants (T &f, tree type)
|
|||
/* Floating-point NaN. */
|
||||
real_nan (&f.nan.rv (), "", 1, mode);
|
||||
|
||||
/* Signalling floating-point NaN. */
|
||||
real_nan (&f.snan.rv (), "", 0, mode);
|
||||
|
||||
/* Floating-point +Infinity if the target supports infinities. */
|
||||
real_inf (&f.infinity.rv ());
|
||||
|
||||
|
@ -142,19 +138,19 @@ Target::_init (const Param &)
|
|||
/* Define what type to use for size_t, ptrdiff_t. */
|
||||
if (this->ptrsize == 8)
|
||||
{
|
||||
global.params.isLP64 = true;
|
||||
Type::tsize_t = Type::basic[Tuns64];
|
||||
Type::tptrdiff_t = Type::basic[Tint64];
|
||||
this->isLP64 = true;
|
||||
Type::tsize_t = Type::basic[(int)TY::Tuns64];
|
||||
Type::tptrdiff_t = Type::basic[(int)TY::Tint64];
|
||||
}
|
||||
else if (this->ptrsize == 4)
|
||||
{
|
||||
Type::tsize_t = Type::basic[Tuns32];
|
||||
Type::tptrdiff_t = Type::basic[Tint32];
|
||||
Type::tsize_t = Type::basic[(int)TY::Tuns32];
|
||||
Type::tptrdiff_t = Type::basic[(int)TY::Tint32];
|
||||
}
|
||||
else if (this->ptrsize == 2)
|
||||
{
|
||||
Type::tsize_t = Type::basic[Tuns16];
|
||||
Type::tptrdiff_t = Type::basic[Tint16];
|
||||
Type::tsize_t = Type::basic[(int)TY::Tuns16];
|
||||
Type::tptrdiff_t = Type::basic[(int)TY::Tint16];
|
||||
}
|
||||
else
|
||||
sorry ("D does not support pointers on this target.");
|
||||
|
@ -164,15 +160,7 @@ Target::_init (const Param &)
|
|||
/* Set-up target C ABI. */
|
||||
this->c.longsize = int_size_in_bytes (long_integer_type_node);
|
||||
this->c.long_doublesize = int_size_in_bytes (long_double_type_node);
|
||||
|
||||
/* Define what type to use for wchar_t. We don't want to support wide
|
||||
characters less than "short" in D. */
|
||||
if (WCHAR_TYPE_SIZE == 32)
|
||||
this->c.twchar_t = Type::basic[Tdchar];
|
||||
else if (WCHAR_TYPE_SIZE == 16)
|
||||
this->c.twchar_t = Type::basic[Twchar];
|
||||
else
|
||||
sorry ("D does not support wide characters on this target.");
|
||||
this->c.wchar_tsize = (WCHAR_TYPE_SIZE / BITS_PER_UNIT);
|
||||
|
||||
/* Set-up target C++ ABI. */
|
||||
this->cpp.reverseOverloads = false;
|
||||
|
@ -182,6 +170,12 @@ Target::_init (const Param &)
|
|||
/* Set-up target Objective-C ABI. */
|
||||
this->objc.supported = false;
|
||||
|
||||
/* Set-up environmental settings. */
|
||||
this->obj_ext = "o";
|
||||
this->lib_ext = "a";
|
||||
this->dll_ext = "so";
|
||||
this->run_noext = true;
|
||||
|
||||
/* Initialize all compile-time properties for floating-point types.
|
||||
Should ensure that our real_t type is able to represent real_value. */
|
||||
gcc_assert (sizeof (real_t) >= sizeof (real_value));
|
||||
|
@ -273,7 +267,7 @@ Target::isVectorTypeSupported (int sz, Type *type)
|
|||
type = Type::tuns8;
|
||||
|
||||
/* No support for non-trivial types, complex types, or booleans. */
|
||||
if (!type->isTypeBasic () || type->iscomplex () || type->ty == Tbool)
|
||||
if (!type->isTypeBasic () || type->iscomplex () || type->ty == TY::Tbool)
|
||||
return 2;
|
||||
|
||||
/* In [simd/vector extensions], which vector types are supported depends on
|
||||
|
@ -293,9 +287,9 @@ Target::isVectorTypeSupported (int sz, Type *type)
|
|||
Returns true if the operation is supported or type is not a vector. */
|
||||
|
||||
bool
|
||||
Target::isVectorOpSupported (Type *type, TOK op, Type *)
|
||||
Target::isVectorOpSupported (Type *type, unsigned op, Type *)
|
||||
{
|
||||
if (type->ty != Tvector)
|
||||
if (type->ty != TY::Tvector)
|
||||
return true;
|
||||
|
||||
/* Don't support if type is non-scalar, such as __vector(void[]). */
|
||||
|
@ -322,18 +316,10 @@ Target::isVectorOpSupported (Type *type, TOK op, Type *)
|
|||
/* Logical operators must have a result type of bool. */
|
||||
return false;
|
||||
|
||||
case TOKue:
|
||||
case TOKlg:
|
||||
case TOKule:
|
||||
case TOKul:
|
||||
case TOKuge:
|
||||
case TOKug:
|
||||
case TOKle:
|
||||
case TOKlt:
|
||||
case TOKge:
|
||||
case TOKgt:
|
||||
case TOKleg:
|
||||
case TOKunord:
|
||||
case TOKequal:
|
||||
case TOKnotequal:
|
||||
case TOKidentity:
|
||||
|
@ -379,7 +365,8 @@ TargetCPP::thunkMangle (FuncDeclaration *fd, int offset)
|
|||
const char *
|
||||
TargetCPP::typeMangle (Type *type)
|
||||
{
|
||||
if (type->isTypeBasic () || type->ty == Tvector || type->ty == Tstruct)
|
||||
if (type->isTypeBasic () || type->ty == TY::Tvector
|
||||
|| type->ty == TY::Tstruct)
|
||||
{
|
||||
tree ctype = build_ctype (type);
|
||||
return targetm.mangle_type (ctype);
|
||||
|
@ -400,14 +387,14 @@ TargetCPP::parameterType (Parameter *arg)
|
|||
else if (arg->storageClass & STClazy)
|
||||
{
|
||||
/* Mangle as delegate. */
|
||||
Type *td = TypeFunction::create (NULL, t, VARARGnone, LINKd);
|
||||
td = TypeDelegate::create (td);
|
||||
t = t->merge2 ();
|
||||
TypeFunction *tf = TypeFunction::create (NULL, t, VARARGnone, LINK::d);
|
||||
TypeDelegate *td = TypeDelegate::create (tf);
|
||||
t = td->merge2 ();
|
||||
}
|
||||
|
||||
/* Could be a va_list, which we mangle as a pointer. */
|
||||
Type *tvalist = target.va_listType (Loc (), NULL);
|
||||
if (t->ty == Tsarray && tvalist->ty == Tsarray)
|
||||
if (t->ty == TY::Tsarray && tvalist->ty == TY::Tsarray)
|
||||
{
|
||||
Type *tb = t->toBasetype ()->mutableOf ();
|
||||
if (tb == tvalist)
|
||||
|
@ -450,10 +437,10 @@ Target::systemLinkage (void)
|
|||
/* In [attribute/linkage], `System' is the same as `Windows' on Windows
|
||||
platforms, and `C' on other platforms. */
|
||||
if (link_system)
|
||||
return LINKwindows;
|
||||
return LINK::windows;
|
||||
}
|
||||
|
||||
return LINKc;
|
||||
return LINK::c;
|
||||
}
|
||||
|
||||
/* Generate a TypeTuple of the equivalent types used to determine if a
|
||||
|
@ -477,12 +464,12 @@ Target::isReturnOnStack (TypeFunction *tf, bool)
|
|||
/* Need the back-end type to determine this, but this is called from the
|
||||
frontend before semantic processing is finished. An accurate value
|
||||
is not currently needed anyway. */
|
||||
if (tf->isref)
|
||||
if (tf->isref ())
|
||||
return false;
|
||||
|
||||
Type *tn = tf->next->toBasetype ();
|
||||
|
||||
return (tn->ty == Tstruct || tn->ty == Tsarray);
|
||||
return (tn->ty == TY::Tstruct || tn->ty == TY::Tsarray);
|
||||
}
|
||||
|
||||
/* Add all target info in HANDLERS to D_TARGET_INFO_TABLE for use by
|
||||
|
@ -575,12 +562,49 @@ Target::getTargetInfo (const char *key, const Loc &loc)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the implementation for object monitors is always defined
|
||||
* in the D runtime library (rt/monitor_.d). */
|
||||
/* Returns true if the callee invokes destructors for arguments. */
|
||||
|
||||
bool
|
||||
Target::isCalleeDestroyingArgs (TypeFunction *tf)
|
||||
{
|
||||
return tf->linkage == LINK::d;
|
||||
}
|
||||
|
||||
/* Returns true if the implementation for object monitors is always defined
|
||||
in the D runtime library (rt/monitor_.d). */
|
||||
|
||||
bool
|
||||
Target::libraryObjectMonitors (FuncDeclaration *, Statement *)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Decides whether an `in' parameter of the specified POD type PARAM_TYPE is to
|
||||
be passed by reference or by valie. This is used only when compiling with
|
||||
`-fpreview=in' enabled. */
|
||||
|
||||
bool
|
||||
Target::preferPassByRef (Type *param_type)
|
||||
{
|
||||
if (param_type->size () == SIZE_INVALID)
|
||||
return false;
|
||||
|
||||
tree type = build_ctype (param_type);
|
||||
|
||||
/* Prefer a `ref' if the type is an aggregate, and its size is greater than
|
||||
its alignment. */
|
||||
if (AGGREGATE_TYPE_P (type)
|
||||
&& (!valid_constant_size_p (TYPE_SIZE_UNIT (type))
|
||||
|| compare_tree_int (TYPE_SIZE_UNIT (type), TYPE_ALIGN (type)) > 0))
|
||||
return true;
|
||||
|
||||
/* If the back-end is always going to pass this by invisible reference. */
|
||||
if (pass_by_reference (NULL, function_arg_info (type, true)))
|
||||
return true;
|
||||
|
||||
/* If returning the parameter means the caller will do RVO. */
|
||||
if (targetm.calls.return_in_memory (type, NULL_TREE))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -617,7 +617,6 @@ extern void add_import_paths (const char *, const char *, bool);
|
|||
|
||||
/* In d-lang.cc. */
|
||||
extern void d_add_builtin_module (Module *);
|
||||
extern void d_add_entrypoint_module (Module *, Module *);
|
||||
extern d_tree_node_structure_enum d_tree_node_structure (lang_tree_node *);
|
||||
extern struct lang_type *build_lang_type (Type *);
|
||||
extern struct lang_decl *build_lang_decl (Declaration *);
|
||||
|
|
166
gcc/d/decl.cc
166
gcc/d/decl.cc
|
@ -106,9 +106,9 @@ gcc_attribute_p (Dsymbol *decl)
|
|||
{
|
||||
ModuleDeclaration *md = decl->getModule ()->md;
|
||||
|
||||
if (md && md->packages && md->packages->length == 1)
|
||||
if (md && md->packages.length == 1)
|
||||
{
|
||||
if (!strcmp ((*md->packages)[0]->toChars (), "gcc")
|
||||
if (!strcmp (md->packages.ptr[0]->toChars (), "gcc")
|
||||
&& !strcmp (md->id->toChars (), "attributes"))
|
||||
return true;
|
||||
}
|
||||
|
@ -116,6 +116,59 @@ gcc_attribute_p (Dsymbol *decl)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Subroutine of pragma declaration visitor for marking the function in the
|
||||
defined in SYM as a global constructor or destructor. If ISCTOR is true,
|
||||
then we're applying pragma(crt_constructor). */
|
||||
|
||||
static int
|
||||
apply_pragma_crt (Dsymbol *sym, bool isctor)
|
||||
{
|
||||
AttribDeclaration *ad = sym->isAttribDeclaration ();
|
||||
if (ad != NULL)
|
||||
{
|
||||
int nested = 0;
|
||||
|
||||
/* Walk all declarations of the attribute scope. */
|
||||
Dsymbols *ds = ad->include (NULL);
|
||||
if (ds)
|
||||
{
|
||||
for (size_t i = 0; i < ds->length; i++)
|
||||
nested += apply_pragma_crt ((*ds)[i], isctor);
|
||||
}
|
||||
|
||||
return nested;
|
||||
}
|
||||
|
||||
FuncDeclaration *fd = sym->isFuncDeclaration ();
|
||||
if (fd != NULL)
|
||||
{
|
||||
tree decl = get_decl_tree (fd);
|
||||
|
||||
/* Apply flags to the function. */
|
||||
if (isctor)
|
||||
{
|
||||
DECL_STATIC_CONSTRUCTOR (decl) = 1;
|
||||
decl_init_priority_insert (decl, DEFAULT_INIT_PRIORITY);
|
||||
}
|
||||
else
|
||||
{
|
||||
DECL_STATIC_DESTRUCTOR (decl) = 1;
|
||||
decl_fini_priority_insert (decl, DEFAULT_INIT_PRIORITY);
|
||||
}
|
||||
|
||||
if (fd->linkage != LINK::c)
|
||||
{
|
||||
error_at (make_location_t (fd->loc),
|
||||
"must be %<extern(C)%> for %<pragma(%s)%>",
|
||||
isctor ? "crt_constructor" : "crt_destructor");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Implements the visitor interface to lower all Declaration AST classes
|
||||
emitted from the D Front-end to GCC trees.
|
||||
All visit methods accept one parameter D, which holds the frontend AST
|
||||
|
@ -246,19 +299,31 @@ public:
|
|||
}
|
||||
|
||||
/* Pragmas are a way to pass special information to the compiler and to add
|
||||
vendor specific extensions to D. We don't do anything here, yet. */
|
||||
vendor specific extensions to D. */
|
||||
|
||||
void visit (PragmaDeclaration *d)
|
||||
{
|
||||
if (!global.params.ignoreUnsupportedPragmas)
|
||||
if (d->ident == Identifier::idPool ("lib")
|
||||
|| d->ident == Identifier::idPool ("startaddress"))
|
||||
{
|
||||
if (d->ident == Identifier::idPool ("lib")
|
||||
|| d->ident == Identifier::idPool ("startaddress"))
|
||||
if (!global.params.ignoreUnsupportedPragmas)
|
||||
{
|
||||
warning_at (make_location_t (d->loc), OPT_Wunknown_pragmas,
|
||||
"pragma(%s) not implemented", d->ident->toChars ());
|
||||
}
|
||||
}
|
||||
else if (d->ident == Identifier::idPool ("crt_constructor")
|
||||
|| d->ident == Identifier::idPool ("crt_destructor"))
|
||||
{
|
||||
/* Handle pragma(crt_constructor) and pragma(crt_destructor). Apply
|
||||
flag to indicate that the functions enclosed should run automatically
|
||||
at the beginning or end of execution. */
|
||||
bool isctor = (d->ident == Identifier::idPool ("crt_constructor"));
|
||||
|
||||
if (apply_pragma_crt (d, isctor) > 1)
|
||||
error_at (make_location_t (d->loc),
|
||||
"can only apply to a single declaration");
|
||||
}
|
||||
|
||||
visit ((AttribDeclaration *) d);
|
||||
}
|
||||
|
@ -311,14 +376,14 @@ public:
|
|||
nested members. Only applies to classes or structs. */
|
||||
Type *tb = fd->type->nextOf ()->baseElemOf ();
|
||||
|
||||
while (tb->ty == Tarray || tb->ty == Tpointer)
|
||||
while (tb->ty == TY::Tarray || tb->ty == TY::Tpointer)
|
||||
tb = tb->nextOf ()->baseElemOf ();
|
||||
|
||||
TemplateInstance *ti = NULL;
|
||||
|
||||
if (tb->ty == Tstruct)
|
||||
if (tb->ty == TY::Tstruct)
|
||||
ti = tb->isTypeStruct ()->sym->isInstantiated ();
|
||||
else if (tb->ty == Tclass)
|
||||
else if (tb->ty == TY::Tclass)
|
||||
ti = tb->isTypeClass ()->sym->isInstantiated ();
|
||||
|
||||
/* Return type is instantiated from this template declaration, walk over
|
||||
|
@ -360,7 +425,7 @@ public:
|
|||
if (d->semanticRun >= PASSobj)
|
||||
return;
|
||||
|
||||
if (d->type->ty == Terror)
|
||||
if (d->type->ty == TY::Terror)
|
||||
{
|
||||
error_at (make_location_t (d->loc),
|
||||
"had semantic errors when compiling");
|
||||
|
@ -447,7 +512,8 @@ public:
|
|||
if (fd2->isFuture ())
|
||||
continue;
|
||||
|
||||
if (fd->leastAsSpecialized (fd2) || fd2->leastAsSpecialized (fd))
|
||||
if (fd->leastAsSpecialized (fd2) != MATCH::nomatch
|
||||
|| fd2->leastAsSpecialized (fd) != MATCH::nomatch)
|
||||
{
|
||||
error_at (make_location_t (fd->loc), "use of %qs",
|
||||
fd->toPrettyChars ());
|
||||
|
@ -474,7 +540,7 @@ public:
|
|||
if (d->semanticRun >= PASSobj)
|
||||
return;
|
||||
|
||||
if (d->type->ty == Terror)
|
||||
if (d->type->ty == TY::Terror)
|
||||
{
|
||||
error_at (make_location_t (d->loc),
|
||||
"had semantic errors when compiling");
|
||||
|
@ -495,7 +561,8 @@ public:
|
|||
|
||||
/* Generate C symbols. */
|
||||
d->csym = get_classinfo_decl (d);
|
||||
d->vtblsym = get_vtable_decl (d);
|
||||
Dsymbol *vtblsym = d->vtblSymbol ();
|
||||
vtblsym->csym = get_vtable_decl (d);
|
||||
tree sinit = aggregate_initializer_decl (d);
|
||||
|
||||
/* Generate static initializer. */
|
||||
|
@ -527,9 +594,9 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
DECL_INITIAL (d->vtblsym)
|
||||
= build_constructor (TREE_TYPE (d->vtblsym), elms);
|
||||
d_finish_decl (d->vtblsym);
|
||||
DECL_INITIAL (vtblsym->csym)
|
||||
= build_constructor (TREE_TYPE (vtblsym->csym), elms);
|
||||
d_finish_decl (vtblsym->csym);
|
||||
|
||||
/* Add this decl to the current binding level. */
|
||||
tree ctype = TREE_TYPE (build_ctype (d->type));
|
||||
|
@ -547,7 +614,7 @@ public:
|
|||
if (d->semanticRun >= PASSobj)
|
||||
return;
|
||||
|
||||
if (d->type->ty == Terror)
|
||||
if (d->type->ty == TY::Terror)
|
||||
{
|
||||
error_at (make_location_t (d->loc),
|
||||
"had semantic errors when compiling");
|
||||
|
@ -590,7 +657,7 @@ public:
|
|||
if (d->semanticRun >= PASSobj)
|
||||
return;
|
||||
|
||||
if (d->errors || d->type->ty == Terror)
|
||||
if (d->errors || d->type->ty == TY::Terror)
|
||||
{
|
||||
error_at (make_location_t (d->loc),
|
||||
"had semantic errors when compiling");
|
||||
|
@ -629,7 +696,7 @@ public:
|
|||
if (d->semanticRun >= PASSobj)
|
||||
return;
|
||||
|
||||
if (d->type->ty == Terror)
|
||||
if (d->type->ty == TY::Terror)
|
||||
{
|
||||
error_at (make_location_t (d->loc),
|
||||
"had semantic errors when compiling");
|
||||
|
@ -695,7 +762,7 @@ public:
|
|||
|
||||
/* Frontend should have already caught this. */
|
||||
gcc_assert (!integer_zerop (size)
|
||||
|| d->type->toBasetype ()->ty == Tsarray);
|
||||
|| d->type->toBasetype ()->ty == TY::Tsarray);
|
||||
|
||||
d_finish_decl (decl);
|
||||
|
||||
|
@ -770,7 +837,7 @@ public:
|
|||
/* Check if any errors occurred when running semantic. */
|
||||
if (TypeFunction *tf = d->type->isTypeFunction ())
|
||||
{
|
||||
if (tf->next == NULL || tf->next->ty == Terror)
|
||||
if (tf->next == NULL || tf->next->ty == TY::Terror)
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1183,6 +1250,17 @@ get_symbol_decl (Declaration *decl)
|
|||
}
|
||||
else if (TREE_CODE (decl->csym) == FUNCTION_DECL)
|
||||
{
|
||||
/* Dual-context functions require the code generation to build an array
|
||||
for the context pointer of the function, making the delicate task of
|
||||
tracking which context to follow when encountering a non-local symbol,
|
||||
and so are a not planned to be supported. */
|
||||
if (fd->needThis () && !fd->isMember2 ())
|
||||
{
|
||||
fatal_error (make_location_t (fd->loc),
|
||||
"function requires a dual-context, which is not yet "
|
||||
"supported by GDC");
|
||||
}
|
||||
|
||||
/* The real function type may differ from its declaration. */
|
||||
tree fntype = TREE_TYPE (decl->csym);
|
||||
tree newfntype = NULL_TREE;
|
||||
|
@ -1238,9 +1316,9 @@ get_symbol_decl (Declaration *decl)
|
|||
|
||||
/* In [pragma/inline], functions decorated with `pragma(inline)' affects
|
||||
whether they are inlined or not. */
|
||||
if (fd->inlining == PINLINEalways)
|
||||
if (fd->inlining == PINLINE::always)
|
||||
DECL_DECLARED_INLINE_P (decl->csym) = 1;
|
||||
else if (fd->inlining == PINLINEnever)
|
||||
else if (fd->inlining == PINLINE::never)
|
||||
DECL_UNINLINABLE (decl->csym) = 1;
|
||||
|
||||
/* Function was declared `naked'. */
|
||||
|
@ -1254,13 +1332,6 @@ get_symbol_decl (Declaration *decl)
|
|||
if (fd->generated)
|
||||
DECL_ARTIFICIAL (decl->csym) = 1;
|
||||
|
||||
/* Vector array operations are always compiler generated. */
|
||||
if (fd->isArrayOp)
|
||||
{
|
||||
DECL_ARTIFICIAL (decl->csym) = 1;
|
||||
DECL_DECLARED_INLINE_P (decl->csym) = 1;
|
||||
}
|
||||
|
||||
/* Ensure and require contracts are lexically nested in the function they
|
||||
part of, but are always publicly callable. */
|
||||
if (fd->ident == Identifier::idPool ("ensure")
|
||||
|
@ -1271,7 +1342,7 @@ get_symbol_decl (Declaration *decl)
|
|||
DECL_FINAL_P (decl->csym) = 1;
|
||||
|
||||
/* Function is of type `noreturn' or `typeof(*null)'. */
|
||||
if (fd->type->nextOf ()->ty == Tnoreturn)
|
||||
if (fd->type->nextOf ()->ty == TY::Tnoreturn)
|
||||
TREE_THIS_VOLATILE (decl->csym) = 1;
|
||||
|
||||
/* Check whether this function is expanded by the frontend. */
|
||||
|
@ -1298,10 +1369,10 @@ get_symbol_decl (Declaration *decl)
|
|||
if (decl->storage_class & STCvolatile)
|
||||
TREE_THIS_VOLATILE (decl->csym) = 1;
|
||||
|
||||
/* Protection attributes are used by the debugger. */
|
||||
if (decl->protection.kind == Prot::private_)
|
||||
/* Visibility attributes are used by the debugger. */
|
||||
if (decl->visibility.kind == Visibility::private_)
|
||||
TREE_PRIVATE (decl->csym) = 1;
|
||||
else if (decl->protection.kind == Prot::protected_)
|
||||
else if (decl->visibility.kind == Visibility::protected_)
|
||||
TREE_PROTECTED (decl->csym) = 1;
|
||||
|
||||
/* Likewise, so could the deprecated attribute. */
|
||||
|
@ -1794,7 +1865,7 @@ make_thunk (FuncDeclaration *decl, int offset)
|
|||
forcing a D local thunk to be emitted. */
|
||||
const char *ident;
|
||||
|
||||
if (decl->linkage == LINKcpp)
|
||||
if (decl->linkage == LINK::cpp)
|
||||
ident = target.cpp.thunkMangle (decl, offset);
|
||||
else
|
||||
{
|
||||
|
@ -1810,7 +1881,9 @@ make_thunk (FuncDeclaration *decl, int offset)
|
|||
SET_DECL_ASSEMBLER_NAME (thunk, DECL_NAME (thunk));
|
||||
|
||||
d_keep (thunk);
|
||||
free (CONST_CAST (char *, ident));
|
||||
|
||||
if (decl->linkage != LINK::cpp)
|
||||
free (CONST_CAST (char *, ident));
|
||||
|
||||
if (!DECL_EXTERNAL (function))
|
||||
finish_thunk (thunk, function);
|
||||
|
@ -1989,26 +2062,27 @@ d_mark_needed (tree decl)
|
|||
tree
|
||||
get_vtable_decl (ClassDeclaration *decl)
|
||||
{
|
||||
if (decl->vtblsym)
|
||||
return decl->vtblsym;
|
||||
if (decl->vtblsym && decl->vtblsym->csym)
|
||||
return decl->vtblsym->csym;
|
||||
|
||||
tree ident = mangle_internal_decl (decl, "__vtbl", "Z");
|
||||
/* Note: Using a static array type for the VAR_DECL, the DECL_INITIAL value
|
||||
will have a different type. However the back-end seems to accept this. */
|
||||
tree type = build_ctype (Type::tvoidptr->sarrayOf (decl->vtbl.length));
|
||||
|
||||
decl->vtblsym = declare_extern_var (ident, type);
|
||||
DECL_LANG_SPECIFIC (decl->vtblsym) = build_lang_decl (NULL);
|
||||
Dsymbol *vtblsym = decl->vtblSymbol ();
|
||||
vtblsym->csym = declare_extern_var (ident, type);
|
||||
DECL_LANG_SPECIFIC (vtblsym->csym) = build_lang_decl (NULL);
|
||||
|
||||
/* Class is a reference, want the record type. */
|
||||
DECL_CONTEXT (decl->vtblsym) = TREE_TYPE (build_ctype (decl->type));
|
||||
TREE_READONLY (decl->vtblsym) = 1;
|
||||
DECL_VIRTUAL_P (decl->vtblsym) = 1;
|
||||
DECL_CONTEXT (vtblsym->csym) = TREE_TYPE (build_ctype (decl->type));
|
||||
TREE_READONLY (vtblsym->csym) = 1;
|
||||
DECL_VIRTUAL_P (vtblsym->csym) = 1;
|
||||
|
||||
SET_DECL_ALIGN (decl->vtblsym, TARGET_VTABLE_ENTRY_ALIGN);
|
||||
DECL_USER_ALIGN (decl->vtblsym) = true;
|
||||
SET_DECL_ALIGN (vtblsym->csym, TARGET_VTABLE_ENTRY_ALIGN);
|
||||
DECL_USER_ALIGN (vtblsym->csym) = true;
|
||||
|
||||
return decl->vtblsym;
|
||||
return vtblsym->csym;
|
||||
}
|
||||
|
||||
/* Helper function of build_class_instance. Find the field inside aggregate
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
27e388b4c4d292cac25811496aaf79341c05c940
|
||||
b8384668f28741ad5884fc055a2bdb9c05fd95ec
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/dmd repository.
|
||||
|
|
259
gcc/d/dmd/README.md
Normal file
259
gcc/d/dmd/README.md
Normal file
|
@ -0,0 +1,259 @@
|
|||
# DMD Source code
|
||||
|
||||
This is the source code to the DMD compiler
|
||||
for the D Programming Language defined in the documents at
|
||||
http://dlang.org/
|
||||
|
||||
These sources are free, they are redistributable and modifiable
|
||||
under the terms of the Boost Software License, Version 1.0.
|
||||
The terms of this license are in the file boostlicense.txt,
|
||||
or see http://www.boost.org/LICENSE_1_0.txt.
|
||||
|
||||
If a particular file has a different license in it, that overrides
|
||||
this license for that file.
|
||||
|
||||
-Walter Bright
|
||||
|
||||
## Directory structure
|
||||
|
||||
| Folder | Purpose |
|
||||
|--------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| [dmd/](https://github.com/dlang/dmd/tree/master/src/dmd) | The dmd driver and front-end |
|
||||
| [dmd/backend/](https://github.com/dlang/dmd/tree/master/src/dmd/backend) | Code generation for x86 or x86-64. Shared by the [Digital Mars C compiler](https://github.com/DigitalMars/Compiler/), but not [LDC](https://github.com/ldc-developers/ldc) or [GDC](https://gdcproject.org/). |
|
||||
| [dmd/root/](https://github.com/dlang/dmd/tree/master/src/dmd/root) | Meant as a portable utility library, but ["it wasn't very good and the only project left using it is dmd"](https://github.com/dlang/dmd/pull/9844#issuecomment-498479516). |
|
||||
|
||||
DMD has a mostly flat directory structure, so this section aims to divide all source files into logical groups for easier navigation.
|
||||
The groups are roughly ordered by how late they appear in the compilation process.
|
||||
Note that these groups have no strict meaning, the category assignments are a bit subjective.
|
||||
|
||||
### Driver
|
||||
|
||||
| File | Purpose |
|
||||
|-----------------------------------------------------------------------------|-----------------------------------------------------------------------|
|
||||
| [mars.d](https://github.com/dlang/dmd/blob/master/src/dmd/mars.d) | The entry point. Contains `main`. |
|
||||
| [cli.d](https://github.com/dlang/dmd/blob/master/src/dmd/cli.d) | Define the command line interface |
|
||||
| [globals.d](https://github.com/dlang/dmd/blob/master/src/dmd/globals.d) | Define a structure storing command line options |
|
||||
| [dinifile.d](https://github.com/dlang/dmd/blob/master/src/dmd/dinifile.d) | Parse settings from .ini file (`sc.ini` / `dmd.conf`) |
|
||||
| [vsoptions.d](https://github.com/dlang/dmd/blob/master/src/dmd/vsoptions.d) | Detect the Microsoft Visual Studio toolchain for linking |
|
||||
| [frontend.d](https://github.com/dlang/dmd/blob/master/src/dmd/frontend.d) | An interface for using DMD as a library |
|
||||
| [errors.d](https://github.com/dlang/dmd/blob/master/src/dmd/errors.d) | Error reporting functionality |
|
||||
| [target.d](https://github.com/dlang/dmd/blob/master/src/dmd/target.d) | Manage target-specific parameters for cross-compiling (for LDC/GDC) |
|
||||
| [compiler.d](https://github.com/dlang/dmd/blob/master/src/dmd/compiler.d) | Describe a back-end compiler and implements compiler-specific actions |
|
||||
|
||||
### Lexing / parsing
|
||||
|
||||
| File | Purpose |
|
||||
|-----------------------------------------------------------------------|----------------------------------------------------------------------|
|
||||
| [lexer.d](https://github.com/dlang/dmd/blob/master/src/dmd/lexer.d) | Convert source code into tokens for the D and ImportC parsers |
|
||||
| [entity.d](https://github.com/dlang/dmd/blob/master/src/dmd/entity.d) | Define "\\&Entity;" escape sequence for strings / character literals |
|
||||
| [tokens.d](https://github.com/dlang/dmd/blob/master/src/dmd/tokens.d) | Define lexical tokens. |
|
||||
| [parse.d](https://github.com/dlang/dmd/blob/master/src/dmd/parse.d) | D parser, converting tokens into an Abstract Syntax Tree (AST) |
|
||||
| [cparse.d](https://github.com/dlang/dmd/blob/master/src/dmd/cparse.d) | ImportC parser, converting tokens into an Abstract Syntax Tree (AST) |
|
||||
|
||||
### Semantic analysis
|
||||
|
||||
**Symbols and declarations**
|
||||
|
||||
| File | Purpose |
|
||||
|---------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|
|
||||
| [dsymbol.d](https://github.com/dlang/dmd/blob/master/src/dmd/dsymbol.d) | Base class for a D symbol, e.g. a variable, function, module, enum etc. |
|
||||
| [identifier.d](https://github.com/dlang/dmd/blob/master/src/dmd/identifier.d) | Represents the name of a `Dsymbol` |
|
||||
| [id.d](https://github.com/dlang/dmd/blob/master/src/dmd/id.d) | Define strings for pre-defined identifiers (e.g. `sizeof`, `string`) |
|
||||
| [dscope.d](https://github.com/dlang/dmd/blob/master/src/dmd/dscope.d) | Define a 'scope' on which symbol lookup can be performed |
|
||||
| [dtemplate.d](https://github.com/dlang/dmd/blob/master/src/dmd/dtemplate.d) | A template declaration or instance |
|
||||
| [dmodule.d](https://github.com/dlang/dmd/blob/master/src/dmd/dmodule.d) | Define a package and module |
|
||||
| [mtype.d](https://github.com/dlang/dmd/blob/master/src/dmd/mtype.d) | Define expression types such as `int`, `char[]`, `void function()` |
|
||||
| [arraytypes.d](https://github.com/dlang/dmd/blob/master/src/dmd/arraytypes.d) | For certain Declaration nodes of type `T`, provides aliases for `Array!T` |
|
||||
| [declaration.d](https://github.com/dlang/dmd/blob/master/src/dmd/declaration.d) | Misc. declarations of `alias`, variables, type tuples, `ClassInfo` etc. |
|
||||
| [denum.d](https://github.com/dlang/dmd/blob/master/src/dmd/denum.d) | Defines `enum` declarations and enum members |
|
||||
| [attrib.d](https://github.com/dlang/dmd/blob/master/src/dmd/nogc.d) | Declarations of 'attributes' such as `private`, `pragma()`, `immutable`, `@UDA`, `align`, `extern(C++)` and more |
|
||||
| [func.d](https://github.com/dlang/dmd/blob/master/src/dmd/func.d) | Define a function declaration (includes function literals, `invariant`, `unittest`) |
|
||||
| [dversion.d](https://github.com/dlang/dmd/blob/master/src/dmd/dversion.d) | Defines a version symbol, e.g. `version = ident`, `debug = ident` |
|
||||
|
||||
**AST nodes**
|
||||
|
||||
| File | Purpose |
|
||||
|-----------------------------------------------------------------------------------|-------------------------------------------------------------|
|
||||
| [ast_node.d](https://github.com/dlang/dmd/blob/master/src/dmd/ast_node.d) | Define an abstract AST node class |
|
||||
| [astbase.d](https://github.com/dlang/dmd/blob/master/src/dmd/astbase.d) | Namespace of AST nodes that can be produced by the parser |
|
||||
| [astcodegen.d](https://github.com/dlang/dmd/blob/master/src/dmd/astcodegen.d) | Namespace of AST nodes of a AST ready for code generation |
|
||||
| [astenums.d](https://github.com/dlang/dmd/blob/master/src/dmd/astenums.d) | Enums common to DMD and AST |
|
||||
| [expression.d](https://github.com/dlang/dmd/blob/master/src/dmd/expression.d) | Define expression AST nodes |
|
||||
| [statement.d](https://github.com/dlang/dmd/blob/master/src/dmd/statement.d) | Define statement AST nodes |
|
||||
| [staticassert.d](https://github.com/dlang/dmd/blob/master/src/dmd/staticassert.d) | Define a `static assert` AST node |
|
||||
| [aggregate.d](https://github.com/dlang/dmd/blob/master/src/dmd/aggregate.d) | Define an aggregate (`struct`, `union` or `class`) AST node |
|
||||
| [dclass.d](https://github.com/dlang/dmd/blob/master/src/dmd/dclass.d) | Define a `class` AST node |
|
||||
| [dstruct.d](https://github.com/dlang/dmd/blob/master/src/dmd/dstruct.d) | Define a `struct` or `union` AST node |
|
||||
| [init.d](https://github.com/dlang/dmd/blob/master/src/dmd/init.d) | Define variable initializers |
|
||||
|
||||
**AST visitors**
|
||||
|
||||
| File | Purpose |
|
||||
|-----------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
|
||||
| [parsetimevisitor.d](https://github.com/dlang/dmd/blob/master/src/dmd/parsetimevisitor.d) | General [visitor](https://en.wikipedia.org/wiki/Visitor_pattern) for AST nodes |
|
||||
| [permissivevisitor.d](https://github.com/dlang/dmd/blob/master/src/dmd/permissivevisitor.d) | Subclass of ParseTimeVisitor that does not `assert(0)` on unimplemented nodes |
|
||||
| [strictvisitor.d](https://github.com/dlang/dmd/blob/master/src/dmd/strictvisitor.d) | Visitor that forces derived classes to implement `visit` for every possible node |
|
||||
| [visitor.d](https://github.com/dlang/dmd/blob/master/src/dmd/visitor.d) | A visitor implementing `visit` for all nodes present in the compiler |
|
||||
| [transitivevisitor.d](https://github.com/dlang/dmd/blob/master/src/dmd/transitivevisitor.d) | Provide a mixin template with visit methods for the parse time AST |
|
||||
| [apply.d](https://github.com/dlang/dmd/blob/master/src/dmd/apply.d) | Depth-first expression visitor |
|
||||
| [sapply.d](https://github.com/dlang/dmd/blob/master/src/dmd/sapply.d) | Depth-first statement visitor |
|
||||
| [statement_rewrite_walker.d](https://github.com/dlang/dmd/blob/master/src/dmd/statement_rewrite_walker.d) | Statement visitor that allows replacing the currently visited node |
|
||||
|
||||
**Semantic passes**
|
||||
|
||||
| File | Purpose |
|
||||
|-------------------------------------------------------------------------------------------|-------------------------------------------------------------------|
|
||||
| [dsymbolsem.d](https://github.com/dlang/dmd/blob/master/src/dmd/dsymbolsem.d) | Do semantic 1 pass (symbol identifiers/types) |
|
||||
| [semantic2.d](https://github.com/dlang/dmd/blob/master/src/dmd/semantic2.d) | Do semantic 2 pass (symbol initializers) |
|
||||
| [semantic3.d](https://github.com/dlang/dmd/blob/master/src/dmd/semantic3.d) | Do semantic 3 pass (function bodies) |
|
||||
| [inline.d](https://github.com/dlang/dmd/blob/master/src/dmd/inline.d) | Do inline pass (optimization pass that dmd does in the front-end) |
|
||||
| [inlinecost.d](https://github.com/dlang/dmd/blob/master/src/dmd/inlinecost.d) | Compute the cost of inlining a function call. |
|
||||
| [expressionsem.d](https://github.com/dlang/dmd/blob/master/src/dmd/expressionsem.d) | Do semantic analysis for expressions |
|
||||
| [statementsem.d](https://github.com/dlang/dmd/blob/master/src/dmd/statementsem.d) | Do semantic analysis for statements |
|
||||
| [initsem.d](https://github.com/dlang/dmd/blob/master/src/dmd/initsem.d) | Do semantic analysis for initializers |
|
||||
| [templateparamsem.d](https://github.com/dlang/dmd/blob/master/src/dmd/templateparamsem.d) | Do semantic analysis for template parameters |
|
||||
| [typesem.d](https://github.com/dlang/dmd/blob/master/src/dmd/typesem.d) | Do semantic analysis for types |
|
||||
|
||||
**Semantic helpers**
|
||||
|
||||
| File | Purpose |
|
||||
|-------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
|
||||
| [opover.d](https://github.com/dlang/dmd/blob/master/src/dmd/opover.d) | Operator overloading |
|
||||
| [clone.d](https://github.com/dlang/dmd/blob/master/src/dmd/dsymbolsem.d) | Generate automatic `opEquals`, `opAssign` and constructors for structs |
|
||||
| [blockexit.d](https://github.com/dlang/dmd/blob/master/src/dmd/blockexit.d) | Find out in what ways control flow can exit a block |
|
||||
| [ctorflow.d](https://github.com/dlang/dmd/blob/master/src/dmd/ctorflow.d) | Control flow in constructors |
|
||||
| [constfold.d](https://github.com/dlang/dmd/blob/master/src/dmd/constfold.d) | Do constant folding of arithmetic expressions |
|
||||
| [optimize.d](https://github.com/dlang/dmd/blob/master/src/dmd/optimize.d) | Do constant folding more generally |
|
||||
| [dcast.d](https://github.com/dlang/dmd/blob/master/src/dmd/dcast.d) | Implicit or explicit cast(), finding common types e.g. in `x ? a : b`, integral promotions |
|
||||
| [impcnvtab.d](https://github.com/dlang/dmd/blob/master/src/dmd/impcnvtab.d) | Define an implicit conversion table for basic types |
|
||||
| [sideeffect.d](https://github.com/dlang/dmd/blob/master/src/dmd/sideeffect.d) | Extract side-effects of expressions for certain lowerings. |
|
||||
|
||||
**Compile Time Function Execution (CTFE)**
|
||||
|
||||
| File | Purpose |
|
||||
|-------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|
|
||||
| [dinterpret.d](https://github.com/dlang/dmd/blob/master/src/dmd/dinterpret.d) | CTFE entry point |
|
||||
| [ctfeexpr.d](https://github.com/dlang/dmd/blob/master/src/dmd/ctfeexpr.d) | CTFE for expressions involving pointers, slices, array concatenation etc. |
|
||||
| [builtin.d](https://github.com/dlang/dmd/blob/master/src/dmd/builtin.d) | Allow CTFE of certain external functions (`core.math`, `std.math` and `core.bitop`) |
|
||||
|
||||
### Specific language features
|
||||
|
||||
**Attribute checks**
|
||||
|
||||
| File | Purpose |
|
||||
|---------------------------------------------------------------------------|----------------------------------------|
|
||||
| [nogc.d](https://github.com/dlang/dmd/blob/master/src/dmd/nogc.d) | `@nogc` checks |
|
||||
| [safe.d](https://github.com/dlang/dmd/blob/master/src/dmd/safe.d) | `@safe` checks |
|
||||
| [canthrow.d](https://github.com/dlang/dmd/blob/master/src/dmd/canthrow.d) | `nothrow` checks |
|
||||
| [escape.d](https://github.com/dlang/dmd/blob/master/src/dmd/escape.d) | `scope` checks |
|
||||
| [access.d](https://github.com/dlang/dmd/blob/master/src/dmd/access.d) | `public` / `private` checks |
|
||||
| [ob.d](https://github.com/dlang/dmd/blob/master/src/dmd/ob.d) | Ownership / borrowing (`@live`) checks |
|
||||
|
||||
**Inline Assembly**
|
||||
|
||||
| File | Purpose |
|
||||
|-------------------------------------------------------------------------|-------------------------------------------|
|
||||
| [iasm.d](https://github.com/dlang/dmd/blob/master/src/dmd/iasm.d) | Inline assembly depending on the compiler |
|
||||
| [iasmdmd.d](https://github.com/dlang/dmd/blob/master/src/dmd/iasmdmd.d) | Inline assembly for DMD |
|
||||
| [iasmgcc.d](https://github.com/dlang/dmd/blob/master/src/dmd/iasmgcc.d) | Inline assembly for GDC |
|
||||
|
||||
**Other**
|
||||
|
||||
| File | Purpose |
|
||||
|-------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|
|
||||
| [aliasthis.d](https://github.com/dlang/dmd/blob/master/src/dmd/aliasthis.d) | Resolve implicit conversions for `alias X this` |
|
||||
| [traits.d](https://github.com/dlang/dmd/blob/master/src/dmd/traits.d) | `__traits()` |
|
||||
| [lambdacomp.d](https://github.com/dlang/dmd/blob/master/src/dmd/lambdacomp.d) | `__traits(isSame, x => y, z => w)` |
|
||||
| [cond.d](https://github.com/dlang/dmd/blob/master/src/dmd/cond.d) | Evaluate `static if`, `version` `debug ` |
|
||||
| [staticcond.d](https://github.com/dlang/dmd/blob/master/src/dmd/staticcond.d) | Lazily evaluate static conditions for `static if`, `static assert` and template constraints |
|
||||
| [delegatize.d](https://github.com/dlang/dmd/blob/master/src/dmd/delegatize.d) | Converts expression to delegates for `lazy` parameters |
|
||||
| [eh.d](https://github.com/dlang/dmd/blob/master/src/dmd/eh.d) | Generate tables for exception handling |
|
||||
| [nspace.d](https://github.com/dlang/dmd/blob/master/src/dmd/nspace.d) | Namespace for `extern (C++, Module)` |
|
||||
| [intrange.d](https://github.com/dlang/dmd/blob/master/src/dmd/intrange.d) | [Value range propagation](https://digitalmars.com/articles/b62.html) |
|
||||
| [dimport.d](https://github.com/dlang/dmd/blob/master/src/dmd/dimport.d) | Renamed imports (`import aliasSymbol = pkg1.pkg2.symbol`) |
|
||||
| [arrayop.d](https://github.com/dlang/dmd/blob/master/src/dmd/arrayop.d) | Array operations (`a[] = b[] + c[]`) |
|
||||
| [typinf.d](https://github.com/dlang/dmd/blob/master/src/dmd/typinf.d) | Generate typeinfo for `typeid()` (as well as internals) |
|
||||
|
||||
| File | Purpose |
|
||||
|-----------------------------------------------------------------------------|------------------------------------------------------------------------------------|
|
||||
| [chkformat.d](https://github.com/dlang/dmd/blob/master/src/dmd/chkformat.d) | Validate arguments with format specifiers for `printf` / `scanf` etc. |
|
||||
| [imphint.d](https://github.com/dlang/dmd/blob/master/src/dmd/imphint.d) | Give a suggestion to e.g. `import std.stdio` when `writeln` could not be resolved. |
|
||||
|
||||
### Library files
|
||||
|
||||
| File | Purpose |
|
||||
|-------------------------------------------------------------------------------|------------------------------------------------------|
|
||||
| [lib.d](https://github.com/dlang/dmd/blob/master/src/dmd/lib.d) | Abstract library class |
|
||||
| [libelf.d](https://github.com/dlang/dmd/blob/master/src/dmd/libelf.d) | Library in ELF format (Unix) |
|
||||
| [libmach.d](https://github.com/dlang/dmd/blob/master/src/dmd/libmach.d) | Library in Mach-O format (macOS) |
|
||||
| [libmscoff.d](https://github.com/dlang/dmd/blob/master/src/dmd/libmscoff.d) | Library in COFF format (32/64-bit Windows) |
|
||||
| [libomf.d](https://github.com/dlang/dmd/blob/master/src/dmd/libomf.d) | Library in OMF format (legacy 32-bit Windows) |
|
||||
| [scanelf.d](https://github.com/dlang/dmd/blob/master/src/dmd/scanelf.d) | Extract symbol names from a library in ELF format |
|
||||
| [scanmach.d](https://github.com/dlang/dmd/blob/master/src/dmd/scanmach.d) | Extract symbol names from a library in Mach-O format |
|
||||
| [scanmscoff.d](https://github.com/dlang/dmd/blob/master/src/dmd/scanmscoff.d) | Extract symbol names from a library in COFF format |
|
||||
| [scanomf.d](https://github.com/dlang/dmd/blob/master/src/dmd/scanomf.d) | Extract symbol names from a library in OMF format |
|
||||
|
||||
### Code generation / back-end interfacing
|
||||
|
||||
| File | Purpose |
|
||||
|---------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|
|
||||
| [dmsc.d](https://github.com/dlang/dmd/blob/master/src/dmd/dmsc.d) | Configures and initializes the back-end |
|
||||
| [toobj.d](https://github.com/dlang/dmd/blob/master/src/dmd/toobj.d) | Convert an AST that went through all semantic phases into an object file |
|
||||
| [toir.d](https://github.com/dlang/dmd/blob/master/src/dmd/toir.d) | Convert Dsymbols intermediate representation |
|
||||
| [e2ir.d](https://github.com/dlang/dmd/blob/master/src/dmd/e2ir.d) | Convert Expressions to intermediate representation |
|
||||
| [s2ir.d](https://github.com/dlang/dmd/blob/master/src/dmd/s2ir.d) | Convert Statements to intermediate representation |
|
||||
| [stmtstate.d](https://github.com/dlang/dmd/blob/master/src/dmd/stmtstate.d) | Used to help transform statement AST into flow graph |
|
||||
| [toctype.d](https://github.com/dlang/dmd/blob/master/src/dmd/toctype.d) | Convert a D type to a type the back-end understands |
|
||||
| [tocsym.d](https://github.com/dlang/dmd/blob/master/src/dmd/tocsym.d) | Convert a D symbol to a symbol the linker understands (with mangled name) |
|
||||
| [argtypes_x86.d](https://github.com/dlang/dmd/blob/master/src/dmd/argtypes_x86.d) | Convert a D type into simple (register) types for the 32-bit x86 ABI |
|
||||
| [argtypes_sysv_x64.d](https://github.com/dlang/dmd/blob/master/src/dmd/argtypes_sysv_x64.d) | 'argtypes' for the x86_64 System V ABI |
|
||||
| [argtypes_aarch64.d](https://github.com/dlang/dmd/blob/master/src/dmd/argtypes_aarch64.d) | 'argtypes' for the AArch64 ABI |
|
||||
| [glue.d](https://github.com/dlang/dmd/blob/master/src/dmd/glue.d) | Generate the object file for function declarations |
|
||||
| [gluelayer.d](https://github.com/dlang/dmd/blob/master/src/dmd/gluelayer.d) | Declarations for back-end functions that the front-end invokes |
|
||||
| [todt.d](https://github.com/dlang/dmd/blob/master/src/dmd/todt.d) | Convert initializers into structures that the back-end will add to the data segment |
|
||||
| [tocvdebug.d](https://github.com/dlang/dmd/blob/master/src/dmd/tovcdebug.d) | Generate debug info in the CV4 debug format. |
|
||||
| [objc.d](https://github.com/dlang/dmd/blob/master/src/dmd/objc.d) | Objective-C interfacing |
|
||||
| [objc_glue.d](https://github.com/dlang/dmd/blob/master/src/dmd/objc_glue.d) | Glue code for Objective-C interop. |
|
||||
|
||||
**Name mangling**
|
||||
|
||||
| File | Purpose |
|
||||
|-----------------------------------------------------------------------------------|------------------------------------------------------------------|
|
||||
| [cppmangle.d](https://github.com/dlang/dmd/blob/master/src/dmd/cppmangle.d) | C++ name mangling |
|
||||
| [cppmanglewin.d](https://github.com/dlang/dmd/blob/master/src/dmd/cppmanglewin.d) | C++ name mangling for Windows |
|
||||
| [dmangle.d](https://github.com/dlang/dmd/blob/master/src/dmd/dmangle.d) | D [name mangling](https://dlang.org/spec/abi.html#name_mangling) |
|
||||
|
||||
### Linking
|
||||
|
||||
| File | Purpose |
|
||||
|-------------------------------------------------------------------|-----------------------------------------|
|
||||
| [link.d](https://github.com/dlang/dmd/blob/master/src/dmd/link.d) | Invoke the linker as a separate process |
|
||||
|
||||
### Special output
|
||||
|
||||
| File | Purpose |
|
||||
|-----------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|
|
||||
| [doc.d](https://github.com/dlang/dmd/blob/master/src/dmd/doc.d) | [Documentation generation](https://dlang.org/spec/ddoc.html) |
|
||||
| [dmacro.d](https://github.com/dlang/dmd/blob/master/src/dmd/dmacro.d) | DDoc macro processing |
|
||||
| [hdrgen.d](https://github.com/dlang/dmd/blob/master/src/dmd/hdrgen.d) | Convert an AST into D source code for `.di` header generation, as well as `-vcg-ast` and error messages |
|
||||
| [json.d](https://github.com/dlang/dmd/blob/master/src/dmd/json.d) | Describe the module in a `.json` file for the `-X` flag |
|
||||
| [dtoh.d](https://github.com/dlang/dmd/blob/master/src/dmd/dtoh.d) | C++ header generation from D source files |
|
||||
|
||||
### Utility
|
||||
|
||||
Note: many other utilities are in [dmd/root](https://github.com/dlang/dmd/tree/master/src/dmd/root).
|
||||
|
||||
| File | Purpose |
|
||||
|-----------------------------------------------------------------------------|---------------------------------------------------|
|
||||
| [env.d](https://github.com/dlang/dmd/blob/master/src/dmd/env.d) | Modify environment variables |
|
||||
| [console.d](https://github.com/dlang/dmd/blob/master/src/dmd/console.d) | Print error messages in color |
|
||||
| [utf.d](https://github.com/dlang/dmd/blob/master/src/dmd/utf.d) | Encoding/decoding Unicode text |
|
||||
| [filecache.d](https://github.com/dlang/dmd/blob/master/src/dmd/filecache.d) | Keep file contents in memory |
|
||||
| [utils.d](https://github.com/dlang/dmd/blob/master/src/dmd/utils.d) | Utility functions related to files and file paths |
|
||||
| [complex.d](https://github.com/dlang/dmd/blob/master/src/dmd/complex.d) | A complex number type |
|
||||
|
||||
| File | Purpose |
|
||||
|---------------------------------------------------------------------------------|---------------------------------------------------------------|
|
||||
| [asttypename.d](https://github.com/dlang/dmd/blob/master/src/dmd/asttypename.d) | Print the internal name of an AST node (for debugging only) |
|
||||
| [printast.d](https://github.com/dlang/dmd/blob/master/src/dmd/printast.d) | Print the AST data structure |
|
||||
| [foreachvar.d](https://github.com/dlang/dmd/blob/master/src/dmd/foreachvar.d) | Used in `ob.d` to iterate over all variables in an expression |
|
1
gcc/d/dmd/VERSION
Normal file
1
gcc/d/dmd/VERSION
Normal file
|
@ -0,0 +1 @@
|
|||
v2.097.2
|
|
@ -1,560 +0,0 @@
|
|||
/* Compiler implementation of the D programming language
|
||||
* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/D-Programming-Language/dmd/blob/master/src/access.c
|
||||
*/
|
||||
|
||||
#include "root/dsystem.h"
|
||||
#include "root/root.h"
|
||||
#include "root/rmem.h"
|
||||
|
||||
#include "errors.h"
|
||||
#include "enum.h"
|
||||
#include "aggregate.h"
|
||||
#include "init.h"
|
||||
#include "attrib.h"
|
||||
#include "scope.h"
|
||||
#include "id.h"
|
||||
#include "mtype.h"
|
||||
#include "declaration.h"
|
||||
#include "aggregate.h"
|
||||
#include "expression.h"
|
||||
#include "module.h"
|
||||
#include "template.h"
|
||||
|
||||
/* Code to do access checks
|
||||
*/
|
||||
|
||||
bool hasPackageAccess(Scope *sc, Dsymbol *s);
|
||||
bool hasPackageAccess(Module *mod, Dsymbol *s);
|
||||
bool hasPrivateAccess(AggregateDeclaration *ad, Dsymbol *smember);
|
||||
bool isFriendOf(AggregateDeclaration *ad, AggregateDeclaration *cd);
|
||||
static Dsymbol *mostVisibleOverload(Dsymbol *s);
|
||||
|
||||
/****************************************
|
||||
* Return Prot access for Dsymbol smember in this declaration.
|
||||
*/
|
||||
Prot getAccess(AggregateDeclaration *ad, Dsymbol *smember)
|
||||
{
|
||||
Prot access_ret = Prot(Prot::none);
|
||||
|
||||
assert(ad->isStructDeclaration() || ad->isClassDeclaration());
|
||||
if (smember->toParent() == ad)
|
||||
{
|
||||
access_ret = smember->prot();
|
||||
}
|
||||
else if (smember->isDeclaration()->isStatic())
|
||||
{
|
||||
access_ret = smember->prot();
|
||||
}
|
||||
if (ClassDeclaration *cd = ad->isClassDeclaration())
|
||||
{
|
||||
for (size_t i = 0; i < cd->baseclasses->length; i++)
|
||||
{
|
||||
BaseClass *b = (*cd->baseclasses)[i];
|
||||
|
||||
Prot access = getAccess(b->sym, smember);
|
||||
switch (access.kind)
|
||||
{
|
||||
case Prot::none:
|
||||
break;
|
||||
|
||||
case Prot::private_:
|
||||
access_ret = Prot(Prot::none); // private members of base class not accessible
|
||||
break;
|
||||
|
||||
case Prot::package_:
|
||||
case Prot::protected_:
|
||||
case Prot::public_:
|
||||
case Prot::export_:
|
||||
// If access is to be tightened
|
||||
if (Prot::public_ < access.kind)
|
||||
access = Prot(Prot::public_);
|
||||
|
||||
// Pick path with loosest access
|
||||
if (access_ret.isMoreRestrictiveThan(access))
|
||||
access_ret = access;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return access_ret;
|
||||
}
|
||||
|
||||
/********************************************************
|
||||
* Helper function for checkAccess()
|
||||
* Returns:
|
||||
* false is not accessible
|
||||
* true is accessible
|
||||
*/
|
||||
static bool isAccessible(
|
||||
Dsymbol *smember,
|
||||
Dsymbol *sfunc,
|
||||
AggregateDeclaration *dthis,
|
||||
AggregateDeclaration *cdscope)
|
||||
{
|
||||
assert(dthis);
|
||||
|
||||
if (hasPrivateAccess(dthis, sfunc) ||
|
||||
isFriendOf(dthis, cdscope))
|
||||
{
|
||||
if (smember->toParent() == dthis)
|
||||
return true;
|
||||
|
||||
if (ClassDeclaration *cdthis = dthis->isClassDeclaration())
|
||||
{
|
||||
for (size_t i = 0; i < cdthis->baseclasses->length; i++)
|
||||
{
|
||||
BaseClass *b = (*cdthis->baseclasses)[i];
|
||||
Prot access = getAccess(b->sym, smember);
|
||||
if (access.kind >= Prot::protected_ ||
|
||||
isAccessible(smember, sfunc, b->sym, cdscope))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (smember->toParent() != dthis)
|
||||
{
|
||||
if (ClassDeclaration *cdthis = dthis->isClassDeclaration())
|
||||
{
|
||||
for (size_t i = 0; i < cdthis->baseclasses->length; i++)
|
||||
{
|
||||
BaseClass *b = (*cdthis->baseclasses)[i];
|
||||
if (isAccessible(smember, sfunc, b->sym, cdscope))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
* Do access check for member of this class, this class being the
|
||||
* type of the 'this' pointer used to access smember.
|
||||
* Returns true if the member is not accessible.
|
||||
*/
|
||||
bool checkAccess(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember)
|
||||
{
|
||||
FuncDeclaration *f = sc->func;
|
||||
AggregateDeclaration *cdscope = sc->getStructClassScope();
|
||||
|
||||
Dsymbol *smemberparent = smember->toParent();
|
||||
if (!smemberparent || !smemberparent->isAggregateDeclaration())
|
||||
{
|
||||
return false; // then it is accessible
|
||||
}
|
||||
|
||||
// BUG: should enable this check
|
||||
//assert(smember->parent->isBaseOf(this, NULL));
|
||||
|
||||
bool result;
|
||||
Prot access;
|
||||
if (smemberparent == ad)
|
||||
{
|
||||
access = smember->prot();
|
||||
result = access.kind >= Prot::public_ ||
|
||||
hasPrivateAccess(ad, f) ||
|
||||
isFriendOf(ad, cdscope) ||
|
||||
(access.kind == Prot::package_ && hasPackageAccess(sc, smember)) ||
|
||||
ad->getAccessModule() == sc->_module;
|
||||
}
|
||||
else if ((access = getAccess(ad, smember)).kind >= Prot::public_)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
else if (access.kind == Prot::package_ && hasPackageAccess(sc, ad))
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = isAccessible(smember, f, ad, cdscope);
|
||||
}
|
||||
if (!result)
|
||||
{
|
||||
ad->error(loc, "member %s is not accessible", smember->toChars());
|
||||
//printf("smember = %s %s, prot = %d, semanticRun = %d\n",
|
||||
// smember->kind(), smember->toPrettyChars(), smember->prot(), smember->semanticRun);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Determine if this is the same or friend of cd.
|
||||
*/
|
||||
bool isFriendOf(AggregateDeclaration *ad, AggregateDeclaration *cd)
|
||||
{
|
||||
if (ad == cd)
|
||||
return true;
|
||||
|
||||
// Friends if both are in the same module
|
||||
//if (toParent() == cd->toParent())
|
||||
if (cd && ad->getAccessModule() == cd->getAccessModule())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Determine if scope sc has package level access to s.
|
||||
*/
|
||||
bool hasPackageAccess(Scope *sc, Dsymbol *s)
|
||||
{
|
||||
return hasPackageAccess(sc->_module, s);
|
||||
}
|
||||
|
||||
bool hasPackageAccess(Module *mod, Dsymbol *s)
|
||||
{
|
||||
Package *pkg = NULL;
|
||||
|
||||
if (s->prot().pkg)
|
||||
pkg = s->prot().pkg;
|
||||
else
|
||||
{
|
||||
// no explicit package for protection, inferring most qualified one
|
||||
for (; s; s = s->parent)
|
||||
{
|
||||
if (Module *m = s->isModule())
|
||||
{
|
||||
DsymbolTable *dst = Package::resolve(m->md ? m->md->packages : NULL, NULL, NULL);
|
||||
assert(dst);
|
||||
Dsymbol *s2 = dst->lookup(m->ident);
|
||||
assert(s2);
|
||||
Package *p = s2->isPackage();
|
||||
if (p && p->isPackageMod())
|
||||
{
|
||||
pkg = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((pkg = s->isPackage()) != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pkg)
|
||||
{
|
||||
if (pkg == mod->parent)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (pkg->isPackageMod() == mod)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
Dsymbol* ancestor = mod->parent;
|
||||
for (; ancestor; ancestor = ancestor->parent)
|
||||
{
|
||||
if (ancestor == pkg)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Determine if scope sc has protected level access to cd.
|
||||
*/
|
||||
bool hasProtectedAccess(Scope *sc, Dsymbol *s)
|
||||
{
|
||||
if (ClassDeclaration *cd = s->isClassMember()) // also includes interfaces
|
||||
{
|
||||
for (Scope *scx = sc; scx; scx = scx->enclosing)
|
||||
{
|
||||
if (!scx->scopesym)
|
||||
continue;
|
||||
ClassDeclaration *cd2 = scx->scopesym->isClassDeclaration();
|
||||
if (cd2 && cd->isBaseOf(cd2, NULL))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return sc->_module == s->getAccessModule();
|
||||
}
|
||||
|
||||
/**********************************
|
||||
* Determine if smember has access to private members of this declaration.
|
||||
*/
|
||||
bool hasPrivateAccess(AggregateDeclaration *ad, Dsymbol *smember)
|
||||
{
|
||||
if (smember)
|
||||
{
|
||||
AggregateDeclaration *cd = NULL;
|
||||
Dsymbol *smemberparent = smember->toParent();
|
||||
if (smemberparent)
|
||||
cd = smemberparent->isAggregateDeclaration();
|
||||
|
||||
if (ad == cd) // smember is a member of this class
|
||||
{
|
||||
return true; // so we get private access
|
||||
}
|
||||
|
||||
// If both are members of the same module, grant access
|
||||
while (1)
|
||||
{
|
||||
Dsymbol *sp = smember->toParent();
|
||||
if (sp->isFuncDeclaration() && smember->isFuncDeclaration())
|
||||
smember = sp;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (!cd && ad->toParent() == smember->toParent())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!cd && ad->getAccessModule() == smember->getAccessModule())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Check access to d for expression e.d
|
||||
* Returns true if the declaration is not accessible.
|
||||
*/
|
||||
bool checkAccess(Loc loc, Scope *sc, Expression *e, Declaration *d)
|
||||
{
|
||||
if (sc->flags & SCOPEnoaccesscheck)
|
||||
return false;
|
||||
|
||||
if (d->isUnitTestDeclaration())
|
||||
{
|
||||
// Unittests are always accessible.
|
||||
return false;
|
||||
}
|
||||
if (!e)
|
||||
return false;
|
||||
|
||||
if (e->type->ty == Tclass)
|
||||
{
|
||||
// Do access check
|
||||
ClassDeclaration *cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym);
|
||||
if (e->op == TOKsuper)
|
||||
{
|
||||
ClassDeclaration *cd2 = sc->func->toParent()->isClassDeclaration();
|
||||
if (cd2)
|
||||
cd = cd2;
|
||||
}
|
||||
return checkAccess(cd, loc, sc, d);
|
||||
}
|
||||
else if (e->type->ty == Tstruct)
|
||||
{
|
||||
// Do access check
|
||||
StructDeclaration *cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym);
|
||||
return checkAccess(cd, loc, sc, d);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Check access to package/module `p` from scope `sc`.
|
||||
*
|
||||
* Params:
|
||||
* loc = source location for issued error message
|
||||
* sc = scope from which to access to a fully qualified package name
|
||||
* p = the package/module to check access for
|
||||
* Returns: true if the package is not accessible.
|
||||
*
|
||||
* Because a global symbol table tree is used for imported packages/modules,
|
||||
* access to them needs to be checked based on the imports in the scope chain
|
||||
* (see Bugzilla 313).
|
||||
*
|
||||
*/
|
||||
bool checkAccess(Scope *sc, Package *p)
|
||||
{
|
||||
if (sc->_module == p)
|
||||
return false;
|
||||
for (; sc; sc = sc->enclosing)
|
||||
{
|
||||
if (sc->scopesym && sc->scopesym->isPackageAccessible(p, Prot(Prot::private_)))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether symbols `s` is visible in `mod`.
|
||||
*
|
||||
* Params:
|
||||
* mod = lookup origin
|
||||
* s = symbol to check for visibility
|
||||
* Returns: true if s is visible in mod
|
||||
*/
|
||||
bool symbolIsVisible(Module *mod, Dsymbol *s)
|
||||
{
|
||||
// should sort overloads by ascending protection instead of iterating here
|
||||
s = mostVisibleOverload(s);
|
||||
|
||||
switch (s->prot().kind)
|
||||
{
|
||||
case Prot::undefined:
|
||||
return true;
|
||||
case Prot::none:
|
||||
return false; // no access
|
||||
case Prot::private_:
|
||||
return s->getAccessModule() == mod;
|
||||
case Prot::package_:
|
||||
return s->getAccessModule() == mod || hasPackageAccess(mod, s);
|
||||
case Prot::protected_:
|
||||
return s->getAccessModule() == mod;
|
||||
case Prot::public_:
|
||||
case Prot::export_:
|
||||
return true;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as above, but determines the lookup module from symbols `origin`.
|
||||
*/
|
||||
bool symbolIsVisible(Dsymbol *origin, Dsymbol *s)
|
||||
{
|
||||
return symbolIsVisible(origin->getAccessModule(), s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as above but also checks for protected symbols visible from scope `sc`.
|
||||
* Used for qualified name lookup.
|
||||
*
|
||||
* Params:
|
||||
* sc = lookup scope
|
||||
* s = symbol to check for visibility
|
||||
* Returns: true if s is visible by origin
|
||||
*/
|
||||
bool symbolIsVisible(Scope *sc, Dsymbol *s)
|
||||
{
|
||||
s = mostVisibleOverload(s);
|
||||
|
||||
switch (s->prot().kind)
|
||||
{
|
||||
case Prot::undefined:
|
||||
return true;
|
||||
case Prot::none:
|
||||
return false; // no access
|
||||
case Prot::private_:
|
||||
return sc->_module == s->getAccessModule();
|
||||
case Prot::package_:
|
||||
return sc->_module == s->getAccessModule() || hasPackageAccess(sc->_module, s);
|
||||
case Prot::protected_:
|
||||
return hasProtectedAccess(sc, s);
|
||||
case Prot::public_:
|
||||
case Prot::export_:
|
||||
return true;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the most visible overload to check visibility. Later perform an access
|
||||
* check on the resolved overload. This function is similar to overloadApply,
|
||||
* but doesn't recurse nor resolve aliases because protection/visibility is an
|
||||
* attribute of the alias not the aliasee.
|
||||
*/
|
||||
static Dsymbol *mostVisibleOverload(Dsymbol *s)
|
||||
{
|
||||
if (!s->isOverloadable())
|
||||
return s;
|
||||
|
||||
Dsymbol *next = NULL;
|
||||
Dsymbol *fstart = s;
|
||||
Dsymbol *mostVisible = s;
|
||||
for (; s; s = next)
|
||||
{
|
||||
// void func() {}
|
||||
// private void func(int) {}
|
||||
if (FuncDeclaration *fd = s->isFuncDeclaration())
|
||||
next = fd->overnext;
|
||||
// template temp(T) {}
|
||||
// private template temp(T:int) {}
|
||||
else if (TemplateDeclaration *td = s->isTemplateDeclaration())
|
||||
next = td->overnext;
|
||||
// alias common = mod1.func1;
|
||||
// alias common = mod2.func2;
|
||||
else if (FuncAliasDeclaration *fa = s->isFuncAliasDeclaration())
|
||||
next = fa->overnext;
|
||||
// alias common = mod1.templ1;
|
||||
// alias common = mod2.templ2;
|
||||
else if (OverDeclaration *od = s->isOverDeclaration())
|
||||
next = od->overnext;
|
||||
// alias name = sym;
|
||||
// private void name(int) {}
|
||||
else if (AliasDeclaration *ad = s->isAliasDeclaration())
|
||||
{
|
||||
if (!ad->isOverloadable())
|
||||
{
|
||||
//printf("Non overloadable Aliasee in overload list\n");
|
||||
assert(0);
|
||||
}
|
||||
// Yet unresolved aliases store overloads in overnext.
|
||||
if (ad->semanticRun < PASSsemanticdone)
|
||||
next = ad->overnext;
|
||||
else
|
||||
{
|
||||
/* This is a bit messy due to the complicated implementation of
|
||||
* alias. Aliases aren't overloadable themselves, but if their
|
||||
* Aliasee is overloadable they can be converted to an overloadable
|
||||
* alias.
|
||||
*
|
||||
* This is done by replacing the Aliasee w/ FuncAliasDeclaration
|
||||
* (for functions) or OverDeclaration (for templates) which are
|
||||
* simply overloadable aliases w/ weird names.
|
||||
*
|
||||
* Usually aliases should not be resolved for visibility checking
|
||||
* b/c public aliases to private symbols are public. But for the
|
||||
* overloadable alias situation, the Alias (_ad_) has been moved
|
||||
* into it's own Aliasee, leaving a shell that we peel away here.
|
||||
*/
|
||||
Dsymbol *aliasee = ad->toAlias();
|
||||
if (aliasee->isFuncAliasDeclaration() || aliasee->isOverDeclaration())
|
||||
next = aliasee;
|
||||
else
|
||||
{
|
||||
/* A simple alias can be at the end of a function or template overload chain.
|
||||
* It can't have further overloads b/c it would have been
|
||||
* converted to an overloadable alias.
|
||||
*/
|
||||
if (ad->overnext)
|
||||
{
|
||||
//printf("Unresolved overload of alias\n");
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// handled by overloadApply for unknown reason
|
||||
assert(next != ad); // should not alias itself
|
||||
assert(next != fstart); // should not alias the overload list itself
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
if (next && mostVisible->prot().isMoreRestrictiveThan(next->prot()))
|
||||
mostVisible = next;
|
||||
}
|
||||
return mostVisible;
|
||||
}
|
410
gcc/d/dmd/access.d
Normal file
410
gcc/d/dmd/access.d
Normal file
|
@ -0,0 +1,410 @@
|
|||
/**
|
||||
* Enforce visibility contrains such as `public` and `private`.
|
||||
*
|
||||
* Specification: $(LINK2 https://dlang.org/spec/attribute.html#visibility_attributes, Visibility Attributes)
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/access.d, _access.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_access.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/access.d
|
||||
*/
|
||||
|
||||
module dmd.access;
|
||||
|
||||
import dmd.aggregate;
|
||||
import dmd.astenums;
|
||||
import dmd.dclass;
|
||||
import dmd.declaration;
|
||||
import dmd.dmodule;
|
||||
import dmd.dscope;
|
||||
import dmd.dstruct;
|
||||
import dmd.dsymbol;
|
||||
import dmd.errors;
|
||||
import dmd.expression;
|
||||
import dmd.func;
|
||||
import dmd.globals;
|
||||
import dmd.mtype;
|
||||
import dmd.tokens;
|
||||
|
||||
private enum LOG = false;
|
||||
|
||||
|
||||
/*******************************
|
||||
* Do access check for member of this class, this class being the
|
||||
* type of the 'this' pointer used to access smember.
|
||||
* Returns true if the member is not accessible.
|
||||
*/
|
||||
bool checkAccess(AggregateDeclaration ad, Loc loc, Scope* sc, Dsymbol smember)
|
||||
{
|
||||
static if (LOG)
|
||||
{
|
||||
printf("AggregateDeclaration::checkAccess() for %s.%s in function %s() in scope %s\n", ad.toChars(), smember.toChars(), f ? f.toChars() : null, cdscope ? cdscope.toChars() : null);
|
||||
}
|
||||
|
||||
const p = smember.toParent();
|
||||
if (p && p.isTemplateInstance())
|
||||
{
|
||||
return false; // for backward compatibility
|
||||
}
|
||||
|
||||
if (!symbolIsVisible(sc, smember))
|
||||
{
|
||||
// when in @safe code or with -preview=dip1000
|
||||
if (sc.flags & SCOPE.onlysafeaccess)
|
||||
{
|
||||
// if there is a func. ask for it's opinion of safety, and if it considers the access @safe accept it.
|
||||
if (sc.func && !sc.func.setUnsafe())
|
||||
return false;
|
||||
}
|
||||
|
||||
ad.error(loc, "%s `%s` is not accessible%s", smember.kind(), smember.toChars(), (sc.flags & SCOPE.onlysafeaccess) ? " from `@safe` code".ptr : "".ptr);
|
||||
//printf("smember = %s %s, vis = %d, semanticRun = %d\n",
|
||||
// smember.kind(), smember.toPrettyChars(), smember.visible() smember.semanticRun);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Determine if scope sc has package level access to s.
|
||||
*/
|
||||
private bool hasPackageAccess(Scope* sc, Dsymbol s)
|
||||
{
|
||||
return hasPackageAccess(sc._module, s);
|
||||
}
|
||||
|
||||
private bool hasPackageAccess(Module mod, Dsymbol s)
|
||||
{
|
||||
static if (LOG)
|
||||
{
|
||||
printf("hasPackageAccess(s = '%s', mod = '%s', s.visibility.pkg = '%s')\n", s.toChars(), mod.toChars(), s.visible().pkg ? s.visible().pkg.toChars() : "NULL");
|
||||
}
|
||||
Package pkg = null;
|
||||
if (s.visible().pkg)
|
||||
pkg = s.visible().pkg;
|
||||
else
|
||||
{
|
||||
// no explicit package for visibility, inferring most qualified one
|
||||
for (; s; s = s.parent)
|
||||
{
|
||||
if (auto m = s.isModule())
|
||||
{
|
||||
DsymbolTable dst = Package.resolve(m.md ? m.md.packages : null, null, null);
|
||||
assert(dst);
|
||||
Dsymbol s2 = dst.lookup(m.ident);
|
||||
assert(s2);
|
||||
Package p = s2.isPackage();
|
||||
if (p && p.isPackageMod())
|
||||
{
|
||||
pkg = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((pkg = s.isPackage()) !is null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
static if (LOG)
|
||||
{
|
||||
if (pkg)
|
||||
printf("\tsymbol access binds to package '%s'\n", pkg.toChars());
|
||||
}
|
||||
if (pkg)
|
||||
{
|
||||
if (pkg == mod.parent)
|
||||
{
|
||||
static if (LOG)
|
||||
{
|
||||
printf("\tsc is in permitted package for s\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (pkg.isPackageMod() == mod)
|
||||
{
|
||||
static if (LOG)
|
||||
{
|
||||
printf("\ts is in same package.d module as sc\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Dsymbol ancestor = mod.parent;
|
||||
for (; ancestor; ancestor = ancestor.parent)
|
||||
{
|
||||
if (ancestor == pkg)
|
||||
{
|
||||
static if (LOG)
|
||||
{
|
||||
printf("\tsc is in permitted ancestor package for s\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
static if (LOG)
|
||||
{
|
||||
printf("\tno package access\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Determine if scope sc has protected level access to cd.
|
||||
*/
|
||||
private bool hasProtectedAccess(Scope *sc, Dsymbol s)
|
||||
{
|
||||
if (auto cd = s.isClassMember()) // also includes interfaces
|
||||
{
|
||||
for (auto scx = sc; scx; scx = scx.enclosing)
|
||||
{
|
||||
if (!scx.scopesym)
|
||||
continue;
|
||||
auto cd2 = scx.scopesym.isClassDeclaration();
|
||||
if (cd2 && cd.isBaseOf(cd2, null))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return sc._module == s.getAccessModule();
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Check access to d for expression e.d
|
||||
* Returns true if the declaration is not accessible.
|
||||
*/
|
||||
bool checkAccess(Loc loc, Scope* sc, Expression e, Dsymbol d)
|
||||
{
|
||||
if (sc.flags & SCOPE.noaccesscheck)
|
||||
return false;
|
||||
static if (LOG)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
printf("checkAccess(%s . %s)\n", e.toChars(), d.toChars());
|
||||
printf("\te.type = %s\n", e.type.toChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("checkAccess(%s)\n", d.toPrettyChars());
|
||||
}
|
||||
}
|
||||
if (d.isUnitTestDeclaration())
|
||||
{
|
||||
// Unittests are always accessible.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!e)
|
||||
return false;
|
||||
|
||||
if (auto tc = e.type.isTypeClass())
|
||||
{
|
||||
// Do access check
|
||||
ClassDeclaration cd = tc.sym;
|
||||
if (e.op == TOK.super_)
|
||||
{
|
||||
if (ClassDeclaration cd2 = sc.func.toParent().isClassDeclaration())
|
||||
cd = cd2;
|
||||
}
|
||||
return checkAccess(cd, loc, sc, d);
|
||||
}
|
||||
else if (auto ts = e.type.isTypeStruct())
|
||||
{
|
||||
// Do access check
|
||||
StructDeclaration cd = ts.sym;
|
||||
return checkAccess(cd, loc, sc, d);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Check access to package/module `p` from scope `sc`.
|
||||
*
|
||||
* Params:
|
||||
* sc = scope from which to access to a fully qualified package name
|
||||
* p = the package/module to check access for
|
||||
* Returns: true if the package is not accessible.
|
||||
*
|
||||
* Because a global symbol table tree is used for imported packages/modules,
|
||||
* access to them needs to be checked based on the imports in the scope chain
|
||||
* (see https://issues.dlang.org/show_bug.cgi?id=313).
|
||||
*
|
||||
*/
|
||||
bool checkAccess(Scope* sc, Package p)
|
||||
{
|
||||
if (sc._module == p)
|
||||
return false;
|
||||
for (; sc; sc = sc.enclosing)
|
||||
{
|
||||
if (sc.scopesym && sc.scopesym.isPackageAccessible(p, Visibility(Visibility.Kind.private_)))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether symbols `s` is visible in `mod`.
|
||||
*
|
||||
* Params:
|
||||
* mod = lookup origin
|
||||
* s = symbol to check for visibility
|
||||
* Returns: true if s is visible in mod
|
||||
*/
|
||||
bool symbolIsVisible(Module mod, Dsymbol s)
|
||||
{
|
||||
// should sort overloads by ascending visibility instead of iterating here
|
||||
s = mostVisibleOverload(s);
|
||||
final switch (s.visible().kind)
|
||||
{
|
||||
case Visibility.Kind.undefined: return true;
|
||||
case Visibility.Kind.none: return false; // no access
|
||||
case Visibility.Kind.private_: return s.getAccessModule() == mod;
|
||||
case Visibility.Kind.package_: return s.getAccessModule() == mod || hasPackageAccess(mod, s);
|
||||
case Visibility.Kind.protected_: return s.getAccessModule() == mod;
|
||||
case Visibility.Kind.public_, Visibility.Kind.export_: return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as above, but determines the lookup module from symbols `origin`.
|
||||
*/
|
||||
bool symbolIsVisible(Dsymbol origin, Dsymbol s)
|
||||
{
|
||||
return symbolIsVisible(origin.getAccessModule(), s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as above but also checks for protected symbols visible from scope `sc`.
|
||||
* Used for qualified name lookup.
|
||||
*
|
||||
* Params:
|
||||
* sc = lookup scope
|
||||
* s = symbol to check for visibility
|
||||
* Returns: true if s is visible by origin
|
||||
*/
|
||||
bool symbolIsVisible(Scope *sc, Dsymbol s)
|
||||
{
|
||||
s = mostVisibleOverload(s);
|
||||
return checkSymbolAccess(sc, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a symbol is visible from a given scope without taking
|
||||
* into account the most visible overload.
|
||||
*
|
||||
* Params:
|
||||
* sc = lookup scope
|
||||
* s = symbol to check for visibility
|
||||
* Returns: true if s is visible by origin
|
||||
*/
|
||||
bool checkSymbolAccess(Scope *sc, Dsymbol s)
|
||||
{
|
||||
final switch (s.visible().kind)
|
||||
{
|
||||
case Visibility.Kind.undefined: return true;
|
||||
case Visibility.Kind.none: return false; // no access
|
||||
case Visibility.Kind.private_: return sc._module == s.getAccessModule();
|
||||
case Visibility.Kind.package_: return sc._module == s.getAccessModule() || hasPackageAccess(sc._module, s);
|
||||
case Visibility.Kind.protected_: return hasProtectedAccess(sc, s);
|
||||
case Visibility.Kind.public_, Visibility.Kind.export_: return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the most visible overload to check visibility. Later perform an access
|
||||
* check on the resolved overload. This function is similar to overloadApply,
|
||||
* but doesn't recurse nor resolve aliases because visibility is an
|
||||
* attribute of the alias not the aliasee.
|
||||
*/
|
||||
public Dsymbol mostVisibleOverload(Dsymbol s, Module mod = null)
|
||||
{
|
||||
if (!s.isOverloadable())
|
||||
return s;
|
||||
|
||||
Dsymbol next, fstart = s, mostVisible = s;
|
||||
for (; s; s = next)
|
||||
{
|
||||
// void func() {}
|
||||
// private void func(int) {}
|
||||
if (auto fd = s.isFuncDeclaration())
|
||||
next = fd.overnext;
|
||||
// template temp(T) {}
|
||||
// private template temp(T:int) {}
|
||||
else if (auto td = s.isTemplateDeclaration())
|
||||
next = td.overnext;
|
||||
// alias common = mod1.func1;
|
||||
// alias common = mod2.func2;
|
||||
else if (auto fa = s.isFuncAliasDeclaration())
|
||||
next = fa.overnext;
|
||||
// alias common = mod1.templ1;
|
||||
// alias common = mod2.templ2;
|
||||
else if (auto od = s.isOverDeclaration())
|
||||
next = od.overnext;
|
||||
// alias name = sym;
|
||||
// private void name(int) {}
|
||||
else if (auto ad = s.isAliasDeclaration())
|
||||
{
|
||||
assert(ad.isOverloadable || ad.type && ad.type.ty == Terror,
|
||||
"Non overloadable Aliasee in overload list");
|
||||
// Yet unresolved aliases store overloads in overnext.
|
||||
if (ad.semanticRun < PASS.semanticdone)
|
||||
next = ad.overnext;
|
||||
else
|
||||
{
|
||||
/* This is a bit messy due to the complicated implementation of
|
||||
* alias. Aliases aren't overloadable themselves, but if their
|
||||
* Aliasee is overloadable they can be converted to an overloadable
|
||||
* alias.
|
||||
*
|
||||
* This is done by replacing the Aliasee w/ FuncAliasDeclaration
|
||||
* (for functions) or OverDeclaration (for templates) which are
|
||||
* simply overloadable aliases w/ weird names.
|
||||
*
|
||||
* Usually aliases should not be resolved for visibility checking
|
||||
* b/c public aliases to private symbols are public. But for the
|
||||
* overloadable alias situation, the Alias (_ad_) has been moved
|
||||
* into its own Aliasee, leaving a shell that we peel away here.
|
||||
*/
|
||||
auto aliasee = ad.toAlias();
|
||||
if (aliasee.isFuncAliasDeclaration || aliasee.isOverDeclaration)
|
||||
next = aliasee;
|
||||
else
|
||||
{
|
||||
/* A simple alias can be at the end of a function or template overload chain.
|
||||
* It can't have further overloads b/c it would have been
|
||||
* converted to an overloadable alias.
|
||||
*/
|
||||
assert(ad.overnext is null, "Unresolved overload of alias");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// handled by dmd.func.overloadApply for unknown reason
|
||||
assert(next !is ad); // should not alias itself
|
||||
assert(next !is fstart); // should not alias the overload list itself
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
/**
|
||||
* Return the "effective" visibility attribute of a symbol when accessed in a module.
|
||||
* The effective visibility attribute is the same as the regular visibility attribute,
|
||||
* except package() is "private" if the module is outside the package;
|
||||
* otherwise, "public".
|
||||
*/
|
||||
static Visibility visibilitySeenFromModule(Dsymbol d, Module mod = null)
|
||||
{
|
||||
Visibility vis = d.visible();
|
||||
if (mod && vis.kind == Visibility.Kind.package_)
|
||||
{
|
||||
return hasPackageAccess(mod, d) ? Visibility(Visibility.Kind.public_) : Visibility(Visibility.Kind.private_);
|
||||
}
|
||||
return vis;
|
||||
}
|
||||
|
||||
if (next &&
|
||||
visibilitySeenFromModule(mostVisible, mod) < visibilitySeenFromModule(next, mod))
|
||||
mostVisible = next;
|
||||
}
|
||||
return mostVisible;
|
||||
}
|
769
gcc/d/dmd/aggregate.d
Normal file
769
gcc/d/dmd/aggregate.d
Normal file
|
@ -0,0 +1,769 @@
|
|||
/**
|
||||
* Defines a `Dsymbol` representing an aggregate, which is a `struct`, `union` or `class`.
|
||||
*
|
||||
* Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions),
|
||||
* $(LINK2 https://dlang.org/spec/class.html, Class).
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aggregate.d, _aggregate.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_aggregate.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/aggregate.d
|
||||
*/
|
||||
|
||||
module dmd.aggregate;
|
||||
|
||||
import core.stdc.stdio;
|
||||
import core.checkedint;
|
||||
|
||||
import dmd.aliasthis;
|
||||
import dmd.apply;
|
||||
import dmd.arraytypes;
|
||||
import dmd.astenums;
|
||||
import dmd.declaration;
|
||||
import dmd.dscope;
|
||||
import dmd.dstruct;
|
||||
import dmd.dsymbol;
|
||||
import dmd.dsymbolsem;
|
||||
import dmd.dtemplate;
|
||||
import dmd.errors;
|
||||
import dmd.expression;
|
||||
import dmd.func;
|
||||
import dmd.globals;
|
||||
import dmd.id;
|
||||
import dmd.identifier;
|
||||
import dmd.mtype;
|
||||
import dmd.tokens;
|
||||
import dmd.typesem : defaultInit;
|
||||
import dmd.visitor;
|
||||
|
||||
/**
|
||||
* The ClassKind enum is used in AggregateDeclaration AST nodes to
|
||||
* specify the linkage type of the struct/class/interface or if it
|
||||
* is an anonymous class. If the class is anonymous it is also
|
||||
* considered to be a D class.
|
||||
*/
|
||||
enum ClassKind : ubyte
|
||||
{
|
||||
/// the aggregate is a d(efault) class
|
||||
d,
|
||||
/// the aggregate is a C++ struct/class/interface
|
||||
cpp,
|
||||
/// the aggregate is an Objective-C class/interface
|
||||
objc,
|
||||
/// the aggregate is a C struct
|
||||
c,
|
||||
}
|
||||
|
||||
/**
|
||||
* If an aggregate has a pargma(mangle, ...) this holds the information
|
||||
* to mangle.
|
||||
*/
|
||||
struct MangleOverride
|
||||
{
|
||||
Dsymbol agg; // The symbol to copy template parameters from (if any)
|
||||
Identifier id; // the name to override the aggregate's with, defaults to agg.ident
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
* Abstract aggregate as a common ancestor for Class- and StructDeclaration.
|
||||
*/
|
||||
extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
|
||||
{
|
||||
Type type; ///
|
||||
StorageClass storage_class; ///
|
||||
uint structsize; /// size of struct
|
||||
uint alignsize; /// size of struct for alignment purposes
|
||||
VarDeclarations fields; /// VarDeclaration fields
|
||||
Dsymbol deferred; /// any deferred semantic2() or semantic3() symbol
|
||||
|
||||
/// specifies whether this is a D, C++, Objective-C or anonymous struct/class/interface
|
||||
ClassKind classKind;
|
||||
/// Specify whether to mangle the aggregate as a `class` or a `struct`
|
||||
/// This information is used by the MSVC mangler
|
||||
/// Only valid for class and struct. TODO: Merge with ClassKind ?
|
||||
CPPMANGLE cppmangle;
|
||||
|
||||
/// overridden symbol with pragma(mangle, "...") if not null
|
||||
MangleOverride* mangleOverride;
|
||||
|
||||
/**
|
||||
* !=null if is nested
|
||||
* pointing to the dsymbol that directly enclosing it.
|
||||
* 1. The function that enclosing it (nested struct and class)
|
||||
* 2. The class that enclosing it (nested class only)
|
||||
* 3. If enclosing aggregate is template, its enclosing dsymbol.
|
||||
*
|
||||
* See AggregateDeclaraton::makeNested for the details.
|
||||
*/
|
||||
Dsymbol enclosing;
|
||||
|
||||
VarDeclaration vthis; /// 'this' parameter if this aggregate is nested
|
||||
VarDeclaration vthis2; /// 'this' parameter if this aggregate is a template and is nested
|
||||
|
||||
// Special member functions
|
||||
FuncDeclarations invs; /// Array of invariants
|
||||
FuncDeclaration inv; /// Merged invariant calling all members of invs
|
||||
|
||||
/// CtorDeclaration or TemplateDeclaration
|
||||
Dsymbol ctor;
|
||||
|
||||
/// default constructor - should have no arguments, because
|
||||
/// it would be stored in TypeInfo_Class.defaultConstructor
|
||||
CtorDeclaration defaultCtor;
|
||||
|
||||
AliasThis aliasthis; /// forward unresolved lookups to aliasthis
|
||||
|
||||
DtorDeclarations dtors; /// Array of destructors
|
||||
DtorDeclaration dtor; /// aggregate destructor calling dtors and member constructors
|
||||
DtorDeclaration primaryDtor;/// non-deleting C++ destructor, same as dtor for D
|
||||
DtorDeclaration tidtor; /// aggregate destructor used in TypeInfo (must have extern(D) ABI)
|
||||
FuncDeclaration fieldDtor; /// aggregate destructor for just the fields
|
||||
|
||||
Expression getRTInfo; /// pointer to GC info generated by object.RTInfo(this)
|
||||
|
||||
///
|
||||
Visibility visibility;
|
||||
bool noDefaultCtor; /// no default construction
|
||||
bool disableNew; /// disallow allocations using `new`
|
||||
Sizeok sizeok = Sizeok.none; /// set when structsize contains valid data
|
||||
|
||||
final extern (D) this(const ref Loc loc, Identifier id)
|
||||
{
|
||||
super(loc, id);
|
||||
visibility = Visibility(Visibility.Kind.public_);
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Create a new scope from sc.
|
||||
* semantic, semantic2 and semantic3 will use this for aggregate members.
|
||||
*/
|
||||
Scope* newScope(Scope* sc)
|
||||
{
|
||||
auto sc2 = sc.push(this);
|
||||
sc2.stc &= STC.flowThruAggregate;
|
||||
sc2.parent = this;
|
||||
sc2.inunion = isUnionDeclaration();
|
||||
sc2.visibility = Visibility(Visibility.Kind.public_);
|
||||
sc2.explicitVisibility = 0;
|
||||
sc2.aligndecl = null;
|
||||
sc2.userAttribDecl = null;
|
||||
sc2.namespace = null;
|
||||
return sc2;
|
||||
}
|
||||
|
||||
override final void setScope(Scope* sc)
|
||||
{
|
||||
// Might need a scope to resolve forward references. The check for
|
||||
// semanticRun prevents unnecessary setting of _scope during deferred
|
||||
// setScope phases for aggregates which already finished semantic().
|
||||
// See https://issues.dlang.org/show_bug.cgi?id=16607
|
||||
if (semanticRun < PASS.semanticdone)
|
||||
ScopeDsymbol.setScope(sc);
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Returns:
|
||||
* The total number of fields minus the number of hidden fields.
|
||||
*/
|
||||
final size_t nonHiddenFields()
|
||||
{
|
||||
return fields.dim - isNested() - (vthis2 !is null);
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Collect all instance fields, then determine instance size.
|
||||
* Returns:
|
||||
* false if failed to determine the size.
|
||||
*/
|
||||
final bool determineSize(Loc loc)
|
||||
{
|
||||
//printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
|
||||
|
||||
// The previous instance size finalizing had:
|
||||
if (type.ty == Terror)
|
||||
return false; // failed already
|
||||
if (sizeok == Sizeok.done)
|
||||
return true; // succeeded
|
||||
|
||||
if (!members)
|
||||
{
|
||||
error(loc, "unknown size");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_scope)
|
||||
dsymbolSemantic(this, null);
|
||||
|
||||
// Determine the instance size of base class first.
|
||||
if (auto cd = isClassDeclaration())
|
||||
{
|
||||
cd = cd.baseClass;
|
||||
if (cd && !cd.determineSize(loc))
|
||||
goto Lfail;
|
||||
}
|
||||
|
||||
// Determine instance fields when sizeok == Sizeok.none
|
||||
if (!this.determineFields())
|
||||
goto Lfail;
|
||||
if (sizeok != Sizeok.done)
|
||||
finalizeSize();
|
||||
|
||||
// this aggregate type has:
|
||||
if (type.ty == Terror)
|
||||
return false; // marked as invalid during the finalizing.
|
||||
if (sizeok == Sizeok.done)
|
||||
return true; // succeeded to calculate instance size.
|
||||
|
||||
Lfail:
|
||||
// There's unresolvable forward reference.
|
||||
if (type != Type.terror)
|
||||
error(loc, "no size because of forward reference");
|
||||
// Don't cache errors from speculative semantic, might be resolvable later.
|
||||
// https://issues.dlang.org/show_bug.cgi?id=16574
|
||||
if (!global.gag)
|
||||
{
|
||||
type = Type.terror;
|
||||
errors = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
abstract void finalizeSize();
|
||||
|
||||
override final d_uns64 size(const ref Loc loc)
|
||||
{
|
||||
//printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
|
||||
bool ok = determineSize(loc);
|
||||
//printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
|
||||
return ok ? structsize : SIZE_INVALID;
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit
|
||||
* field initializers have unique memory space on instance.
|
||||
* Returns:
|
||||
* true if any errors happen.
|
||||
*/
|
||||
extern (D) final bool checkOverlappedFields()
|
||||
{
|
||||
//printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars());
|
||||
assert(sizeok == Sizeok.done);
|
||||
size_t nfields = fields.dim;
|
||||
if (isNested())
|
||||
{
|
||||
auto cd = isClassDeclaration();
|
||||
if (!cd || !cd.baseClass || !cd.baseClass.isNested())
|
||||
nfields--;
|
||||
if (vthis2 && !(cd && cd.baseClass && cd.baseClass.vthis2))
|
||||
nfields--;
|
||||
}
|
||||
bool errors = false;
|
||||
|
||||
// Fill in missing any elements with default initializers
|
||||
foreach (i; 0 .. nfields)
|
||||
{
|
||||
auto vd = fields[i];
|
||||
if (vd.errors)
|
||||
{
|
||||
errors = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const vdIsVoidInit = vd._init && vd._init.isVoidInitializer();
|
||||
|
||||
// Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
|
||||
foreach (j; 0 .. nfields)
|
||||
{
|
||||
if (i == j)
|
||||
continue;
|
||||
auto v2 = fields[j];
|
||||
if (v2.errors)
|
||||
{
|
||||
errors = true;
|
||||
continue;
|
||||
}
|
||||
if (!vd.isOverlappedWith(v2))
|
||||
continue;
|
||||
|
||||
// vd and v2 are overlapping.
|
||||
vd.overlapped = true;
|
||||
v2.overlapped = true;
|
||||
|
||||
if (!MODimplicitConv(vd.type.mod, v2.type.mod))
|
||||
v2.overlapUnsafe = true;
|
||||
if (!MODimplicitConv(v2.type.mod, vd.type.mod))
|
||||
vd.overlapUnsafe = true;
|
||||
|
||||
if (i > j)
|
||||
continue;
|
||||
|
||||
if (!v2._init)
|
||||
continue;
|
||||
|
||||
if (v2._init.isVoidInitializer())
|
||||
continue;
|
||||
|
||||
if (vd._init && !vdIsVoidInit && v2._init)
|
||||
{
|
||||
.error(loc, "overlapping default initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
|
||||
errors = true;
|
||||
}
|
||||
else if (v2._init && i < j)
|
||||
{
|
||||
.error(v2.loc, "union field `%s` with default initialization `%s` must be before field `%s`",
|
||||
v2.toChars(), v2._init.toChars(), vd.toChars());
|
||||
errors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Fill out remainder of elements[] with default initializers for fields[].
|
||||
* Params:
|
||||
* loc = location
|
||||
* elements = explicit arguments which given to construct object.
|
||||
* ctorinit = true if the elements will be used for default initialization.
|
||||
* Returns:
|
||||
* false if any errors occur.
|
||||
* Otherwise, returns true and the missing arguments will be pushed in elements[].
|
||||
*/
|
||||
final bool fill(Loc loc, Expressions* elements, bool ctorinit)
|
||||
{
|
||||
//printf("AggregateDeclaration::fill() %s\n", toChars());
|
||||
assert(sizeok == Sizeok.done);
|
||||
assert(elements);
|
||||
const nfields = nonHiddenFields();
|
||||
bool errors = false;
|
||||
|
||||
size_t dim = elements.dim;
|
||||
elements.setDim(nfields);
|
||||
foreach (size_t i; dim .. nfields)
|
||||
(*elements)[i] = null;
|
||||
|
||||
// Fill in missing any elements with default initializers
|
||||
foreach (i; 0 .. nfields)
|
||||
{
|
||||
if ((*elements)[i])
|
||||
continue;
|
||||
|
||||
auto vd = fields[i];
|
||||
auto vx = vd;
|
||||
if (vd._init && vd._init.isVoidInitializer())
|
||||
vx = null;
|
||||
|
||||
// Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
|
||||
size_t fieldi = i;
|
||||
foreach (j; 0 .. nfields)
|
||||
{
|
||||
if (i == j)
|
||||
continue;
|
||||
auto v2 = fields[j];
|
||||
if (!vd.isOverlappedWith(v2))
|
||||
continue;
|
||||
|
||||
if ((*elements)[j])
|
||||
{
|
||||
vx = null;
|
||||
break;
|
||||
}
|
||||
if (v2._init && v2._init.isVoidInitializer())
|
||||
continue;
|
||||
|
||||
version (all)
|
||||
{
|
||||
/* Prefer first found non-void-initialized field
|
||||
* union U { int a; int b = 2; }
|
||||
* U u; // Error: overlapping initialization for field a and b
|
||||
*/
|
||||
if (!vx)
|
||||
{
|
||||
vx = v2;
|
||||
fieldi = j;
|
||||
}
|
||||
else if (v2._init)
|
||||
{
|
||||
.error(loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
|
||||
errors = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// fixes https://issues.dlang.org/show_bug.cgi?id=1432 by enabling this path always
|
||||
|
||||
/* Prefer explicitly initialized field
|
||||
* union U { int a; int b = 2; }
|
||||
* U u; // OK (u.b == 2)
|
||||
*/
|
||||
if (!vx || !vx._init && v2._init)
|
||||
{
|
||||
vx = v2;
|
||||
fieldi = j;
|
||||
}
|
||||
else if (vx != vd && !vx.isOverlappedWith(v2))
|
||||
{
|
||||
// Both vx and v2 fills vd, but vx and v2 does not overlap
|
||||
}
|
||||
else if (vx._init && v2._init)
|
||||
{
|
||||
.error(loc, "overlapping default initialization for field `%s` and `%s`",
|
||||
v2.toChars(), vd.toChars());
|
||||
errors = true;
|
||||
}
|
||||
else
|
||||
assert(vx._init || !vx._init && !v2._init);
|
||||
}
|
||||
}
|
||||
if (vx)
|
||||
{
|
||||
Expression e;
|
||||
if (vx.type.size() == 0)
|
||||
{
|
||||
e = null;
|
||||
}
|
||||
else if (vx._init)
|
||||
{
|
||||
assert(!vx._init.isVoidInitializer());
|
||||
if (vx.inuse) // https://issues.dlang.org/show_bug.cgi?id=18057
|
||||
{
|
||||
vx.error(loc, "recursive initialization of field");
|
||||
errors = true;
|
||||
}
|
||||
else
|
||||
e = vx.getConstInitializer(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((vx.storage_class & STC.nodefaultctor) && !ctorinit)
|
||||
{
|
||||
.error(loc, "field `%s.%s` must be initialized because it has no default constructor",
|
||||
type.toChars(), vx.toChars());
|
||||
errors = true;
|
||||
}
|
||||
/* https://issues.dlang.org/show_bug.cgi?id=12509
|
||||
* Get the element of static array type.
|
||||
*/
|
||||
Type telem = vx.type;
|
||||
if (telem.ty == Tsarray)
|
||||
{
|
||||
/* We cannot use Type::baseElemOf() here.
|
||||
* If the bottom of the Tsarray is an enum type, baseElemOf()
|
||||
* will return the base of the enum, and its default initializer
|
||||
* would be different from the enum's.
|
||||
*/
|
||||
TypeSArray tsa;
|
||||
while ((tsa = telem.toBasetype().isTypeSArray()) !is null)
|
||||
telem = tsa.next;
|
||||
if (telem.ty == Tvoid)
|
||||
telem = Type.tuns8.addMod(telem.mod);
|
||||
}
|
||||
if (telem.needsNested() && ctorinit)
|
||||
e = telem.defaultInit(loc);
|
||||
else
|
||||
e = telem.defaultInitLiteral(loc);
|
||||
}
|
||||
(*elements)[fieldi] = e;
|
||||
}
|
||||
}
|
||||
foreach (e; *elements)
|
||||
{
|
||||
if (e && e.op == TOK.error)
|
||||
return false;
|
||||
}
|
||||
|
||||
return !errors;
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Do byte or word alignment as necessary.
|
||||
* Align sizes of 0, as we may not know array sizes yet.
|
||||
* Params:
|
||||
* alignment = struct alignment that is in effect
|
||||
* size = alignment requirement of field
|
||||
* poffset = pointer to offset to be aligned
|
||||
*/
|
||||
extern (D) static void alignmember(structalign_t alignment, uint size, uint* poffset) pure nothrow @safe
|
||||
{
|
||||
//printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset);
|
||||
switch (alignment)
|
||||
{
|
||||
case cast(structalign_t)1:
|
||||
// No alignment
|
||||
break;
|
||||
|
||||
case cast(structalign_t)STRUCTALIGN_DEFAULT:
|
||||
// Alignment in Target::fieldalignsize must match what the
|
||||
// corresponding C compiler's default alignment behavior is.
|
||||
assert(size > 0 && !(size & (size - 1)));
|
||||
*poffset = (*poffset + size - 1) & ~(size - 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Align on alignment boundary, which must be a positive power of 2
|
||||
assert(alignment > 0 && !(alignment & (alignment - 1)));
|
||||
*poffset = (*poffset + alignment - 1) & ~(alignment - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Place a member (mem) into an aggregate (agg), which can be a struct, union or class
|
||||
* Returns:
|
||||
* offset to place field at
|
||||
*
|
||||
* nextoffset: next location in aggregate
|
||||
* memsize: size of member
|
||||
* memalignsize: natural alignment of member
|
||||
* alignment: alignment in effect for this member
|
||||
* paggsize: size of aggregate (updated)
|
||||
* paggalignsize: alignment of aggregate (updated)
|
||||
* isunion: the aggregate is a union
|
||||
*/
|
||||
extern (D) static uint placeField(uint* nextoffset, uint memsize, uint memalignsize,
|
||||
structalign_t alignment, uint* paggsize, uint* paggalignsize, bool isunion)
|
||||
{
|
||||
uint ofs = *nextoffset;
|
||||
|
||||
const uint actualAlignment =
|
||||
alignment == STRUCTALIGN_DEFAULT ? memalignsize : alignment;
|
||||
|
||||
// Ensure no overflow
|
||||
bool overflow;
|
||||
const sz = addu(memsize, actualAlignment, overflow);
|
||||
addu(ofs, sz, overflow);
|
||||
if (overflow) assert(0);
|
||||
|
||||
alignmember(alignment, memalignsize, &ofs);
|
||||
uint memoffset = ofs;
|
||||
ofs += memsize;
|
||||
if (ofs > *paggsize)
|
||||
*paggsize = ofs;
|
||||
if (!isunion)
|
||||
*nextoffset = ofs;
|
||||
|
||||
if (*paggalignsize < actualAlignment)
|
||||
*paggalignsize = actualAlignment;
|
||||
|
||||
return memoffset;
|
||||
}
|
||||
|
||||
override final Type getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
// is aggregate deprecated?
|
||||
override final bool isDeprecated() const
|
||||
{
|
||||
return !!(this.storage_class & STC.deprecated_);
|
||||
}
|
||||
|
||||
/// Flag this aggregate as deprecated
|
||||
final void setDeprecated()
|
||||
{
|
||||
this.storage_class |= STC.deprecated_;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Returns true if there's an extra member which is the 'this'
|
||||
* pointer to the enclosing context (enclosing aggregate or function)
|
||||
*/
|
||||
final bool isNested() const
|
||||
{
|
||||
return enclosing !is null;
|
||||
}
|
||||
|
||||
/* Append vthis field (this.tupleof[$-1]) to make this aggregate type nested.
|
||||
*/
|
||||
extern (D) final void makeNested()
|
||||
{
|
||||
if (enclosing) // if already nested
|
||||
return;
|
||||
if (sizeok == Sizeok.done)
|
||||
return;
|
||||
if (isUnionDeclaration() || isInterfaceDeclaration())
|
||||
return;
|
||||
if (storage_class & STC.static_)
|
||||
return;
|
||||
|
||||
// If nested struct, add in hidden 'this' pointer to outer scope
|
||||
auto s = toParentLocal();
|
||||
if (!s)
|
||||
s = toParent2();
|
||||
if (!s)
|
||||
return;
|
||||
Type t = null;
|
||||
if (auto fd = s.isFuncDeclaration())
|
||||
{
|
||||
enclosing = fd;
|
||||
|
||||
/* https://issues.dlang.org/show_bug.cgi?id=14422
|
||||
* If a nested class parent is a function, its
|
||||
* context pointer (== `outer`) should be void* always.
|
||||
*/
|
||||
t = Type.tvoidptr;
|
||||
}
|
||||
else if (auto ad = s.isAggregateDeclaration())
|
||||
{
|
||||
if (isClassDeclaration() && ad.isClassDeclaration())
|
||||
{
|
||||
enclosing = ad;
|
||||
}
|
||||
else if (isStructDeclaration())
|
||||
{
|
||||
if (auto ti = ad.parent.isTemplateInstance())
|
||||
{
|
||||
enclosing = ti.enclosing;
|
||||
}
|
||||
}
|
||||
t = ad.handleType();
|
||||
}
|
||||
if (enclosing)
|
||||
{
|
||||
//printf("makeNested %s, enclosing = %s\n", toChars(), enclosing.toChars());
|
||||
assert(t);
|
||||
if (t.ty == Tstruct)
|
||||
t = Type.tvoidptr; // t should not be a ref type
|
||||
|
||||
assert(!vthis);
|
||||
vthis = new ThisDeclaration(loc, t);
|
||||
//vthis.storage_class |= STC.ref_;
|
||||
|
||||
// Emulate vthis.addMember()
|
||||
members.push(vthis);
|
||||
|
||||
// Emulate vthis.dsymbolSemantic()
|
||||
vthis.storage_class |= STC.field;
|
||||
vthis.parent = this;
|
||||
vthis.visibility = Visibility(Visibility.Kind.public_);
|
||||
vthis.alignment = t.alignment();
|
||||
vthis.semanticRun = PASS.semanticdone;
|
||||
|
||||
if (sizeok == Sizeok.fwd)
|
||||
fields.push(vthis);
|
||||
|
||||
makeNested2();
|
||||
}
|
||||
}
|
||||
|
||||
/* Append vthis2 field (this.tupleof[$-1]) to add a second context pointer.
|
||||
*/
|
||||
extern (D) final void makeNested2()
|
||||
{
|
||||
if (vthis2)
|
||||
return;
|
||||
if (!vthis)
|
||||
makeNested(); // can't add second before first
|
||||
if (!vthis)
|
||||
return;
|
||||
if (sizeok == Sizeok.done)
|
||||
return;
|
||||
if (isUnionDeclaration() || isInterfaceDeclaration())
|
||||
return;
|
||||
if (storage_class & STC.static_)
|
||||
return;
|
||||
|
||||
auto s0 = toParentLocal();
|
||||
auto s = toParent2();
|
||||
if (!s || !s0 || s == s0)
|
||||
return;
|
||||
auto cd = s.isClassDeclaration();
|
||||
Type t = cd ? cd.type : Type.tvoidptr;
|
||||
|
||||
vthis2 = new ThisDeclaration(loc, t);
|
||||
//vthis2.storage_class |= STC.ref_;
|
||||
|
||||
// Emulate vthis2.addMember()
|
||||
members.push(vthis2);
|
||||
|
||||
// Emulate vthis2.dsymbolSemantic()
|
||||
vthis2.storage_class |= STC.field;
|
||||
vthis2.parent = this;
|
||||
vthis2.visibility = Visibility(Visibility.Kind.public_);
|
||||
vthis2.alignment = t.alignment();
|
||||
vthis2.semanticRun = PASS.semanticdone;
|
||||
|
||||
if (sizeok == Sizeok.fwd)
|
||||
fields.push(vthis2);
|
||||
}
|
||||
|
||||
override final bool isExport() const
|
||||
{
|
||||
return visibility.kind == Visibility.Kind.export_;
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
* Look for constructor declaration.
|
||||
*/
|
||||
final Dsymbol searchCtor()
|
||||
{
|
||||
auto s = search(Loc.initial, Id.ctor);
|
||||
if (s)
|
||||
{
|
||||
if (!(s.isCtorDeclaration() ||
|
||||
s.isTemplateDeclaration() ||
|
||||
s.isOverloadSet()))
|
||||
{
|
||||
s.error("is not a constructor; identifiers starting with `__` are reserved for the implementation");
|
||||
errors = true;
|
||||
s = null;
|
||||
}
|
||||
}
|
||||
if (s && s.toParent() != this)
|
||||
s = null; // search() looks through ancestor classes
|
||||
if (s)
|
||||
{
|
||||
// Finish all constructors semantics to determine this.noDefaultCtor.
|
||||
struct SearchCtor
|
||||
{
|
||||
extern (C++) static int fp(Dsymbol s, void* ctxt)
|
||||
{
|
||||
auto f = s.isCtorDeclaration();
|
||||
if (f && f.semanticRun == PASS.init)
|
||||
f.dsymbolSemantic(null);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < members.dim; i++)
|
||||
{
|
||||
auto sm = (*members)[i];
|
||||
sm.apply(&SearchCtor.fp, null);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
override final Visibility visible() pure nothrow @nogc @safe
|
||||
{
|
||||
return visibility;
|
||||
}
|
||||
|
||||
// 'this' type
|
||||
final Type handleType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
// Does this class have an invariant function?
|
||||
final bool hasInvariant()
|
||||
{
|
||||
return invs.length != 0;
|
||||
}
|
||||
|
||||
// Back end
|
||||
void* sinit; /// initializer symbol
|
||||
|
||||
override final inout(AggregateDeclaration) isAggregateDeclaration() inout
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
{
|
||||
v.visit(this);
|
||||
}
|
||||
}
|
|
@ -10,12 +10,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "root/root.h"
|
||||
|
||||
#include "dsymbol.h"
|
||||
#include "declaration.h"
|
||||
#include "objc.h"
|
||||
|
||||
class AliasThis;
|
||||
class Identifier;
|
||||
class Type;
|
||||
class TypeFunction;
|
||||
|
@ -23,65 +21,51 @@ class Expression;
|
|||
class FuncDeclaration;
|
||||
class CtorDeclaration;
|
||||
class DtorDeclaration;
|
||||
class InvariantDeclaration;
|
||||
class NewDeclaration;
|
||||
class DeleteDeclaration;
|
||||
class InterfaceDeclaration;
|
||||
class TypeInfoClassDeclaration;
|
||||
class VarDeclaration;
|
||||
|
||||
enum Sizeok
|
||||
enum class Sizeok : uint8_t
|
||||
{
|
||||
SIZEOKnone, // size of aggregate is not yet able to compute
|
||||
SIZEOKfwd, // size of aggregate is ready to compute
|
||||
SIZEOKdone // size of aggregate is set correctly
|
||||
none, // size of aggregate is not yet able to compute
|
||||
fwd, // size of aggregate is ready to compute
|
||||
inProcess, // in the midst of computing the size
|
||||
done // size of aggregate is set correctly
|
||||
};
|
||||
|
||||
enum Baseok
|
||||
enum class Baseok : uint8_t
|
||||
{
|
||||
BASEOKnone, // base classes not computed yet
|
||||
BASEOKin, // in process of resolving base classes
|
||||
BASEOKdone, // all base classes are resolved
|
||||
BASEOKsemanticdone // all base classes semantic done
|
||||
none, // base classes not computed yet
|
||||
in, // in process of resolving base classes
|
||||
done, // all base classes are resolved
|
||||
semanticdone // all base classes semantic done
|
||||
};
|
||||
|
||||
enum StructPOD
|
||||
enum class ThreeState : uint8_t
|
||||
{
|
||||
ISPODno, // struct is not POD
|
||||
ISPODyes, // struct is POD
|
||||
ISPODfwd // POD not yet computed
|
||||
none, // value not yet computed
|
||||
no, // value is false
|
||||
yes, // value is true
|
||||
};
|
||||
|
||||
enum Abstract
|
||||
{
|
||||
ABSfwdref = 0, // whether an abstract class is not yet computed
|
||||
ABSyes, // is abstract class
|
||||
ABSno // is not abstract class
|
||||
};
|
||||
|
||||
FuncDeclaration *hasIdentityOpAssign(AggregateDeclaration *ad, Scope *sc);
|
||||
FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc);
|
||||
bool needOpEquals(StructDeclaration *sd);
|
||||
FuncDeclaration *buildOpEquals(StructDeclaration *sd, Scope *sc);
|
||||
FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc);
|
||||
FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc);
|
||||
FuncDeclaration *buildXtoHash(StructDeclaration *ad, Scope *sc);
|
||||
FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc);
|
||||
FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc);
|
||||
FuncDeclaration *buildInv(AggregateDeclaration *ad, Scope *sc);
|
||||
FuncDeclaration *search_toString(StructDeclaration *sd);
|
||||
|
||||
struct ClassKind
|
||||
enum class ClassKind : uint8_t
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
/// the class is a d(efault) class
|
||||
d,
|
||||
/// the class is a C++ interface
|
||||
cpp,
|
||||
/// the class is an Objective-C class/interface
|
||||
objc,
|
||||
};
|
||||
/// the aggregate is a d(efault) struct/class/interface
|
||||
d,
|
||||
/// the aggregate is a C++ struct/class/interface
|
||||
cpp,
|
||||
/// the aggregate is an Objective-C class/interface
|
||||
objc,
|
||||
/// the aggregate is a C struct
|
||||
c,
|
||||
};
|
||||
|
||||
struct MangleOverride
|
||||
{
|
||||
Dsymbol *agg;
|
||||
Identifier *id;
|
||||
};
|
||||
|
||||
class AggregateDeclaration : public ScopeDsymbol
|
||||
|
@ -89,16 +73,16 @@ class AggregateDeclaration : public ScopeDsymbol
|
|||
public:
|
||||
Type *type;
|
||||
StorageClass storage_class;
|
||||
Prot protection;
|
||||
unsigned structsize; // size of struct
|
||||
unsigned alignsize; // size of struct for alignment purposes
|
||||
VarDeclarations fields; // VarDeclaration fields
|
||||
Sizeok sizeok; // set when structsize contains valid data
|
||||
Dsymbol *deferred; // any deferred semantic2() or semantic3() symbol
|
||||
bool isdeprecated; // true if deprecated
|
||||
|
||||
ClassKind::Type classKind; // specifies the linkage type
|
||||
ClassKind classKind; // specifies the linkage type
|
||||
CPPMANGLE cppmangle;
|
||||
|
||||
// overridden symbol with pragma(mangle, "...")
|
||||
MangleOverride *mangleOverride;
|
||||
/* !=NULL if is nested
|
||||
* pointing to the dsymbol that directly enclosing it.
|
||||
* 1. The function that enclosing it (nested struct and class)
|
||||
|
@ -108,11 +92,10 @@ public:
|
|||
*/
|
||||
Dsymbol *enclosing;
|
||||
VarDeclaration *vthis; // 'this' parameter if this aggregate is nested
|
||||
VarDeclaration *vthis2; // 'this' parameter if this aggregate is a template and is nested
|
||||
// Special member functions
|
||||
FuncDeclarations invs; // Array of invariants
|
||||
FuncDeclaration *inv; // invariant
|
||||
NewDeclaration *aggNew; // allocator
|
||||
DeleteDeclaration *aggDelete; // deallocator
|
||||
|
||||
Dsymbol *ctor; // CtorDeclaration or TemplateDeclaration
|
||||
|
||||
|
@ -120,42 +103,44 @@ public:
|
|||
// it would be stored in TypeInfo_Class.defaultConstructor
|
||||
CtorDeclaration *defaultCtor;
|
||||
|
||||
Dsymbol *aliasthis; // forward unresolved lookups to aliasthis
|
||||
bool noDefaultCtor; // no default construction
|
||||
AliasThis *aliasthis; // forward unresolved lookups to aliasthis
|
||||
|
||||
FuncDeclarations dtors; // Array of destructors
|
||||
FuncDeclaration *dtor; // aggregate destructor
|
||||
DtorDeclarations dtors; // Array of destructors
|
||||
DtorDeclaration *dtor; // aggregate destructor
|
||||
DtorDeclaration *primaryDtor; // non-deleting C++ destructor, same as dtor for D
|
||||
DtorDeclaration *tidtor; // aggregate destructor used in TypeInfo (must have extern(D) ABI)
|
||||
FuncDeclaration *fieldDtor; // aggregate destructor for just the fields
|
||||
|
||||
Expression *getRTInfo; // pointer to GC info generated by object.RTInfo(this)
|
||||
|
||||
AggregateDeclaration(Loc loc, Identifier *id);
|
||||
Visibility visibility;
|
||||
bool noDefaultCtor; // no default construction
|
||||
bool disableNew; // disallow allocations using `new`
|
||||
Sizeok sizeok; // set when structsize contains valid data
|
||||
|
||||
virtual Scope *newScope(Scope *sc);
|
||||
void setScope(Scope *sc);
|
||||
bool determineFields();
|
||||
size_t nonHiddenFields();
|
||||
bool determineSize(Loc loc);
|
||||
virtual void finalizeSize() = 0;
|
||||
d_uns64 size(Loc loc);
|
||||
bool checkOverlappedFields();
|
||||
d_uns64 size(const Loc &loc);
|
||||
bool fill(Loc loc, Expressions *elements, bool ctorinit);
|
||||
static void alignmember(structalign_t salign, unsigned size, unsigned *poffset);
|
||||
static unsigned placeField(unsigned *nextoffset,
|
||||
unsigned memsize, unsigned memalignsize, structalign_t memalign,
|
||||
unsigned *paggsize, unsigned *paggalignsize, bool isunion);
|
||||
Type *getType();
|
||||
bool isDeprecated(); // is aggregate deprecated?
|
||||
bool isNested();
|
||||
void makeNested();
|
||||
bool isDeprecated() const; // is aggregate deprecated?
|
||||
void setDeprecated();
|
||||
bool isNested() const;
|
||||
bool isExport() const;
|
||||
Dsymbol *searchCtor();
|
||||
|
||||
Prot prot();
|
||||
Visibility visible();
|
||||
|
||||
// 'this' type
|
||||
Type *handleType() { return type; }
|
||||
|
||||
bool hasInvariant();
|
||||
|
||||
// Back end
|
||||
Symbol *stag; // tag symbol for debug data
|
||||
Symbol *sinit;
|
||||
void *sinit;
|
||||
|
||||
AggregateDeclaration *isAggregateDeclaration() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -163,8 +148,7 @@ public:
|
|||
|
||||
struct StructFlags
|
||||
{
|
||||
typedef unsigned Type;
|
||||
enum Enum
|
||||
enum Type
|
||||
{
|
||||
none = 0x0,
|
||||
hasPointers = 0x1 // NB: should use noPointers as in ClassFlags
|
||||
|
@ -174,9 +158,17 @@ struct StructFlags
|
|||
class StructDeclaration : public AggregateDeclaration
|
||||
{
|
||||
public:
|
||||
int zeroInit; // !=0 if initialize with 0 fill
|
||||
bool zeroInit; // !=0 if initialize with 0 fill
|
||||
bool hasIdentityAssign; // true if has identity opAssign
|
||||
bool hasBlitAssign; // true if opAssign is a blit
|
||||
bool hasIdentityEquals; // true if has identity opEquals
|
||||
bool hasNoFields; // has no fields
|
||||
bool hasCopyCtor; // copy constructor
|
||||
// Even if struct is defined as non-root symbol, some built-in operations
|
||||
// (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo.
|
||||
// For those, today TypeInfo_Struct is generated in COMDAT.
|
||||
bool requestTypeInfo;
|
||||
|
||||
FuncDeclarations postblits; // Array of postblit functions
|
||||
FuncDeclaration *postblit; // aggregate postblit
|
||||
|
||||
|
@ -187,36 +179,30 @@ public:
|
|||
static FuncDeclaration *xerrcmp; // object.xopCmp
|
||||
|
||||
structalign_t alignment; // alignment applied outside of the struct
|
||||
StructPOD ispod; // if struct is POD
|
||||
ThreeState ispod; // if struct is POD
|
||||
|
||||
// For 64 bit Efl function call/return ABI
|
||||
Type *arg1type;
|
||||
Type *arg2type;
|
||||
// ABI-specific type(s) if the struct can be passed in registers
|
||||
TypeTuple *argTypes;
|
||||
|
||||
// Even if struct is defined as non-root symbol, some built-in operations
|
||||
// (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo.
|
||||
// For those, today TypeInfo_Struct is generated in COMDAT.
|
||||
bool requestTypeInfo;
|
||||
|
||||
StructDeclaration(Loc loc, Identifier *id, bool inObject);
|
||||
static StructDeclaration *create(Loc loc, Identifier *id, bool inObject);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
void semanticTypeInfoMembers();
|
||||
StructDeclaration *syntaxCopy(Dsymbol *s);
|
||||
Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
|
||||
const char *kind() const;
|
||||
void finalizeSize();
|
||||
bool fit(Loc loc, Scope *sc, Expressions *elements, Type *stype);
|
||||
bool isPOD();
|
||||
|
||||
StructDeclaration *isStructDeclaration() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
||||
unsigned numArgTypes() const;
|
||||
Type *argType(unsigned index);
|
||||
bool hasRegularCtor(bool checkDisabled = false);
|
||||
};
|
||||
|
||||
class UnionDeclaration : public StructDeclaration
|
||||
{
|
||||
public:
|
||||
UnionDeclaration(Loc loc, Identifier *id);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
UnionDeclaration *syntaxCopy(Dsymbol *s);
|
||||
const char *kind() const;
|
||||
|
||||
UnionDeclaration *isUnionDeclaration() { return this; }
|
||||
|
@ -236,18 +222,14 @@ struct BaseClass
|
|||
DArray<BaseClass> baseInterfaces; // if BaseClass is an interface, these
|
||||
// are a copy of the InterfaceDeclaration::interfaces
|
||||
|
||||
BaseClass();
|
||||
BaseClass(Type *type);
|
||||
|
||||
bool fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance);
|
||||
void copyBaseInterfaces(BaseClasses *);
|
||||
};
|
||||
|
||||
struct ClassFlags
|
||||
{
|
||||
typedef unsigned Type;
|
||||
enum Enum
|
||||
enum Type
|
||||
{
|
||||
none = 0x0,
|
||||
isCOMclass = 0x1,
|
||||
noPointers = 0x2,
|
||||
hasOffTi = 0x4,
|
||||
|
@ -286,15 +268,18 @@ public:
|
|||
|
||||
TypeInfoClassDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration
|
||||
bool com; // true if this is a COM class (meaning it derives from IUnknown)
|
||||
bool isscope; // true if this is a scope class
|
||||
Abstract isabstract; // 0: fwdref, 1: is abstract class, 2: not abstract
|
||||
int inuse; // to prevent recursive attempts
|
||||
bool stack; // true if this is a scope class
|
||||
int cppDtorVtblIndex; // slot reserved for the virtual destructor [extern(C++)]
|
||||
bool inuse; // to prevent recursive attempts
|
||||
|
||||
ThreeState isabstract; // if abstract class
|
||||
Baseok baseok; // set the progress of base classes resolving
|
||||
ObjcClassDeclaration objc; // Data for a class declaration that is needed for the Objective-C integration
|
||||
Symbol *cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr
|
||||
|
||||
ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject = false);
|
||||
static ClassDeclaration *create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
const char *toPrettyChars(bool QualifyTypes = false);
|
||||
ClassDeclaration *syntaxCopy(Dsymbol *s);
|
||||
Scope *newScope(Scope *sc);
|
||||
bool isBaseOf2(ClassDeclaration *cd);
|
||||
|
||||
|
@ -318,9 +303,11 @@ public:
|
|||
const char *kind() const;
|
||||
|
||||
void addLocalClass(ClassDeclarations *);
|
||||
void addObjcSymbols(ClassDeclarations *classes, ClassDeclarations *categories);
|
||||
|
||||
// Back end
|
||||
Symbol *vtblsym;
|
||||
Dsymbol *vtblsym;
|
||||
Dsymbol *vtblSymbol();
|
||||
|
||||
ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -329,11 +316,9 @@ public:
|
|||
class InterfaceDeclaration : public ClassDeclaration
|
||||
{
|
||||
public:
|
||||
InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
InterfaceDeclaration *syntaxCopy(Dsymbol *s);
|
||||
Scope *newScope(Scope *sc);
|
||||
bool isBaseOf(ClassDeclaration *cd, int *poffset);
|
||||
bool isBaseOf(BaseClass *bc, int *poffset);
|
||||
const char *kind() const;
|
||||
int vtblOffset() const;
|
||||
bool isCPPinterface() const;
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
|
||||
/* Compiler implementation of the D programming language
|
||||
* Copyright (C) 2009-2021 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/D-Programming-Language/dmd/blob/master/src/aliasthis.c
|
||||
*/
|
||||
|
||||
#include "root/dsystem.h"
|
||||
|
||||
#include "mars.h"
|
||||
#include "identifier.h"
|
||||
#include "aliasthis.h"
|
||||
#include "scope.h"
|
||||
#include "aggregate.h"
|
||||
#include "dsymbol.h"
|
||||
#include "mtype.h"
|
||||
#include "declaration.h"
|
||||
#include "expression.h"
|
||||
#include "tokens.h"
|
||||
|
||||
Expression *resolveAliasThis(Scope *sc, Expression *e, bool gag)
|
||||
{
|
||||
AggregateDeclaration *ad = isAggregate(e->type);
|
||||
|
||||
if (ad && ad->aliasthis)
|
||||
{
|
||||
unsigned olderrors = gag ? global.startGagging() : 0;
|
||||
|
||||
Loc loc = e->loc;
|
||||
Type *tthis = (e->op == TOKtype ? e->type : NULL);
|
||||
e = new DotIdExp(loc, e, ad->aliasthis->ident);
|
||||
e = expressionSemantic(e, sc);
|
||||
if (tthis && ad->aliasthis->needThis())
|
||||
{
|
||||
if (e->op == TOKvar)
|
||||
{
|
||||
if (FuncDeclaration *fd = ((VarExp *)e)->var->isFuncDeclaration())
|
||||
{
|
||||
// Bugzilla 13009: Support better match for the overloaded alias this.
|
||||
bool hasOverloads = false;
|
||||
if (FuncDeclaration *f = fd->overloadModMatch(loc, tthis, hasOverloads))
|
||||
{
|
||||
if (!hasOverloads)
|
||||
fd = f; // use exact match
|
||||
e = new VarExp(loc, fd, hasOverloads);
|
||||
e->type = f->type;
|
||||
e = new CallExp(loc, e);
|
||||
goto L1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* non-@property function is not called inside typeof(),
|
||||
* so resolve it ahead.
|
||||
*/
|
||||
{
|
||||
int save = sc->intypeof;
|
||||
sc->intypeof = 1; // bypass "need this" error check
|
||||
e = resolveProperties(sc, e);
|
||||
sc->intypeof = save;
|
||||
}
|
||||
|
||||
L1:
|
||||
e = new TypeExp(loc, new TypeTypeof(loc, e));
|
||||
e = expressionSemantic(e, sc);
|
||||
}
|
||||
e = resolveProperties(sc, e);
|
||||
|
||||
if (gag && global.endGagging(olderrors))
|
||||
e = NULL;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
AliasThis::AliasThis(Loc loc, Identifier *ident)
|
||||
: Dsymbol(NULL) // it's anonymous (no identifier)
|
||||
{
|
||||
this->loc = loc;
|
||||
this->ident = ident;
|
||||
}
|
||||
|
||||
Dsymbol *AliasThis::syntaxCopy(Dsymbol *s)
|
||||
{
|
||||
assert(!s);
|
||||
return new AliasThis(loc, ident);
|
||||
}
|
||||
|
||||
const char *AliasThis::kind() const
|
||||
{
|
||||
return "alias this";
|
||||
}
|
202
gcc/d/dmd/aliasthis.d
Normal file
202
gcc/d/dmd/aliasthis.d
Normal file
|
@ -0,0 +1,202 @@
|
|||
/**
|
||||
* Implements the `alias this` symbol.
|
||||
*
|
||||
* Specification: $(LINK2 https://dlang.org/spec/class.html#alias-this, Alias This)
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aliasthis.d, _aliasthis.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_aliasthis.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/aliasthis.d
|
||||
*/
|
||||
|
||||
module dmd.aliasthis;
|
||||
|
||||
import core.stdc.stdio;
|
||||
import dmd.aggregate;
|
||||
import dmd.dscope;
|
||||
import dmd.dsymbol;
|
||||
import dmd.expression;
|
||||
import dmd.expressionsem;
|
||||
import dmd.globals;
|
||||
import dmd.identifier;
|
||||
import dmd.mtype;
|
||||
import dmd.opover;
|
||||
import dmd.tokens;
|
||||
import dmd.visitor;
|
||||
|
||||
/***********************************************************
|
||||
* alias ident this;
|
||||
*/
|
||||
extern (C++) final class AliasThis : Dsymbol
|
||||
{
|
||||
Identifier ident;
|
||||
/// The symbol this `alias this` resolves to
|
||||
Dsymbol sym;
|
||||
/// Whether this `alias this` is deprecated or not
|
||||
bool isDeprecated_;
|
||||
|
||||
extern (D) this(const ref Loc loc, Identifier ident)
|
||||
{
|
||||
super(loc, null); // it's anonymous (no identifier)
|
||||
this.ident = ident;
|
||||
}
|
||||
|
||||
override AliasThis syntaxCopy(Dsymbol s)
|
||||
{
|
||||
assert(!s);
|
||||
auto at = new AliasThis(loc, ident);
|
||||
at.comment = comment;
|
||||
return at;
|
||||
}
|
||||
|
||||
override const(char)* kind() const
|
||||
{
|
||||
return "alias this";
|
||||
}
|
||||
|
||||
AliasThis isAliasThis()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
{
|
||||
v.visit(this);
|
||||
}
|
||||
|
||||
override bool isDeprecated() const
|
||||
{
|
||||
return this.isDeprecated_;
|
||||
}
|
||||
}
|
||||
|
||||
Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false)
|
||||
{
|
||||
for (AggregateDeclaration ad = isAggregate(e.type); ad;)
|
||||
{
|
||||
if (ad.aliasthis)
|
||||
{
|
||||
uint olderrors = gag ? global.startGagging() : 0;
|
||||
Loc loc = e.loc;
|
||||
Type tthis = (e.op == TOK.type ? e.type : null);
|
||||
e = new DotIdExp(loc, e, ad.aliasthis.ident);
|
||||
e = e.expressionSemantic(sc);
|
||||
if (tthis && ad.aliasthis.sym.needThis())
|
||||
{
|
||||
if (e.op == TOK.variable)
|
||||
{
|
||||
if (auto fd = (cast(VarExp)e).var.isFuncDeclaration())
|
||||
{
|
||||
// https://issues.dlang.org/show_bug.cgi?id=13009
|
||||
// Support better match for the overloaded alias this.
|
||||
bool hasOverloads;
|
||||
if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads))
|
||||
{
|
||||
if (!hasOverloads)
|
||||
fd = f; // use exact match
|
||||
e = new VarExp(loc, fd, hasOverloads);
|
||||
e.type = f.type;
|
||||
e = new CallExp(loc, e);
|
||||
goto L1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* non-@property function is not called inside typeof(),
|
||||
* so resolve it ahead.
|
||||
*/
|
||||
{
|
||||
int save = sc.intypeof;
|
||||
sc.intypeof = 1; // bypass "need this" error check
|
||||
e = resolveProperties(sc, e);
|
||||
sc.intypeof = save;
|
||||
}
|
||||
L1:
|
||||
e = new TypeExp(loc, new TypeTypeof(loc, e));
|
||||
e = e.expressionSemantic(sc);
|
||||
}
|
||||
e = resolveProperties(sc, e);
|
||||
if (!gag)
|
||||
ad.aliasthis.checkDeprecatedAliasThis(loc, sc);
|
||||
else if (global.endGagging(olderrors))
|
||||
e = null;
|
||||
}
|
||||
|
||||
import dmd.dclass : ClassDeclaration;
|
||||
auto cd = ad.isClassDeclaration();
|
||||
if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
|
||||
{
|
||||
ad = cd.baseClass;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an `alias this` is deprecated
|
||||
*
|
||||
* Usually one would use `expression.checkDeprecated(scope, aliasthis)` to
|
||||
* check if `expression` uses a deprecated `aliasthis`, but this calls
|
||||
* `toPrettyChars` which lead to the following message:
|
||||
* "Deprecation: alias this `fullyqualified.aggregate.__anonymous` is deprecated"
|
||||
*
|
||||
* Params:
|
||||
* at = The `AliasThis` object to check
|
||||
* loc = `Loc` of the expression triggering the access to `at`
|
||||
* sc = `Scope` of the expression
|
||||
* (deprecations do not trigger in deprecated scopes)
|
||||
*
|
||||
* Returns:
|
||||
* Whether the alias this was reported as deprecated.
|
||||
*/
|
||||
bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc)
|
||||
{
|
||||
import dmd.errors : deprecation, Classification;
|
||||
import dmd.dsymbolsem : getMessage;
|
||||
|
||||
if (global.params.useDeprecated != DiagnosticReporting.off
|
||||
&& at.isDeprecated() && !sc.isDeprecated())
|
||||
{
|
||||
const(char)* message = null;
|
||||
for (Dsymbol p = at; p; p = p.parent)
|
||||
{
|
||||
message = p.depdecl ? p.depdecl.getMessage() : null;
|
||||
if (message)
|
||||
break;
|
||||
}
|
||||
if (message)
|
||||
deprecation(loc, "`alias %s this` is deprecated - %s",
|
||||
at.sym.toChars(), message);
|
||||
else
|
||||
deprecation(loc, "`alias %s this` is deprecated",
|
||||
at.sym.toChars());
|
||||
|
||||
if (auto ti = sc.parent ? sc.parent.isInstantiated() : null)
|
||||
ti.printInstantiationTrace(Classification.deprecation);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* Check and set 'att' if 't' is a recursive 'alias this' type
|
||||
* Params:
|
||||
* att = type reference used to detect recursion
|
||||
* t = 'alias this' type
|
||||
*
|
||||
* Returns:
|
||||
* Whether the 'alias this' is recursive or not
|
||||
*/
|
||||
bool isRecursiveAliasThis(ref Type att, Type t)
|
||||
{
|
||||
auto tb = t.toBasetype();
|
||||
if (att && tb.equivalent(att))
|
||||
return true;
|
||||
else if (!att && tb.checkAliasThisRec())
|
||||
att = tb;
|
||||
return false;
|
||||
}
|
|
@ -5,11 +5,12 @@
|
|||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/dlang/dmd/blob/master/src/aliasthis.h
|
||||
* https://github.com/dlang/dmd/blob/master/src/dmd/aliasthis.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "globals.h"
|
||||
#include "dsymbol.h"
|
||||
|
||||
/**************************************************************/
|
||||
|
@ -19,11 +20,12 @@ class AliasThis : public Dsymbol
|
|||
public:
|
||||
// alias Identifier this;
|
||||
Identifier *ident;
|
||||
Dsymbol *sym;
|
||||
bool isDeprecated_;
|
||||
|
||||
AliasThis(Loc loc, Identifier *ident);
|
||||
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
AliasThis *syntaxCopy(Dsymbol *);
|
||||
const char *kind() const;
|
||||
AliasThis *isAliasThis() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
bool isDeprecated() const { return this->isDeprecated_; }
|
||||
};
|
||||
|
|
|
@ -1,149 +0,0 @@
|
|||
|
||||
/* Compiler implementation of the D programming language
|
||||
* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/D-Programming-Language/dmd/blob/master/src/apply.c
|
||||
*/
|
||||
|
||||
#include "root/dsystem.h"
|
||||
|
||||
#include "mars.h"
|
||||
#include "expression.h"
|
||||
#include "template.h"
|
||||
#include "visitor.h"
|
||||
|
||||
|
||||
/**************************************
|
||||
* An Expression tree walker that will visit each Expression e in the tree,
|
||||
* in depth-first evaluation order, and call fp(e,param) on it.
|
||||
* fp() signals whether the walking continues with its return value:
|
||||
* Returns:
|
||||
* 0 continue
|
||||
* 1 done
|
||||
* It's a bit slower than using virtual functions, but more encapsulated and less brittle.
|
||||
* Creating an iterator for this would be much more complex.
|
||||
*/
|
||||
|
||||
class PostorderExpressionVisitor : public StoppableVisitor
|
||||
{
|
||||
public:
|
||||
StoppableVisitor *v;
|
||||
PostorderExpressionVisitor(StoppableVisitor *v) : v(v) {}
|
||||
|
||||
bool doCond(Expression *e)
|
||||
{
|
||||
if (!stop && e)
|
||||
e->accept(this);
|
||||
return stop;
|
||||
}
|
||||
bool doCond(Expressions *e)
|
||||
{
|
||||
if (!e)
|
||||
return false;
|
||||
for (size_t i = 0; i < e->length && !stop; i++)
|
||||
doCond((*e)[i]);
|
||||
return stop;
|
||||
}
|
||||
bool applyTo(Expression *e)
|
||||
{
|
||||
e->accept(v);
|
||||
stop = v->stop;
|
||||
return true;
|
||||
}
|
||||
|
||||
void visit(Expression *e)
|
||||
{
|
||||
applyTo(e);
|
||||
}
|
||||
|
||||
void visit(NewExp *e)
|
||||
{
|
||||
//printf("NewExp::apply(): %s\n", toChars());
|
||||
|
||||
doCond(e->thisexp) || doCond(e->newargs) || doCond(e->arguments) || applyTo(e);
|
||||
}
|
||||
|
||||
void visit(NewAnonClassExp *e)
|
||||
{
|
||||
//printf("NewAnonClassExp::apply(): %s\n", toChars());
|
||||
|
||||
doCond(e->thisexp) || doCond(e->newargs) || doCond(e->arguments) || applyTo(e);
|
||||
}
|
||||
|
||||
void visit(TypeidExp *e)
|
||||
{
|
||||
doCond(isExpression(e->obj)) || applyTo(e);
|
||||
}
|
||||
|
||||
void visit(UnaExp *e)
|
||||
{
|
||||
doCond(e->e1) || applyTo(e);
|
||||
}
|
||||
|
||||
void visit(BinExp *e)
|
||||
{
|
||||
doCond(e->e1) || doCond(e->e2) || applyTo(e);
|
||||
}
|
||||
|
||||
void visit(AssertExp *e)
|
||||
{
|
||||
//printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
|
||||
doCond(e->e1) || doCond(e->msg) || applyTo(e);
|
||||
}
|
||||
|
||||
void visit(CallExp *e)
|
||||
{
|
||||
//printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
|
||||
doCond(e->e1) || doCond(e->arguments) || applyTo(e);
|
||||
}
|
||||
|
||||
void visit(ArrayExp *e)
|
||||
{
|
||||
//printf("ArrayExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
|
||||
doCond(e->e1) || doCond(e->arguments) || applyTo(e);
|
||||
}
|
||||
|
||||
void visit(SliceExp *e)
|
||||
{
|
||||
doCond(e->e1) || doCond(e->lwr) || doCond(e->upr) || applyTo(e);
|
||||
}
|
||||
|
||||
void visit(ArrayLiteralExp *e)
|
||||
{
|
||||
doCond(e->basis) || doCond(e->elements) || applyTo(e);
|
||||
}
|
||||
|
||||
void visit(AssocArrayLiteralExp *e)
|
||||
{
|
||||
doCond(e->keys) || doCond(e->values) || applyTo(e);
|
||||
}
|
||||
|
||||
void visit(StructLiteralExp *e)
|
||||
{
|
||||
if (e->stageflags & stageApply) return;
|
||||
int old = e->stageflags;
|
||||
e->stageflags |= stageApply;
|
||||
doCond(e->elements) || applyTo(e);
|
||||
e->stageflags = old;
|
||||
}
|
||||
|
||||
void visit(TupleExp *e)
|
||||
{
|
||||
doCond(e->e0) || doCond(e->exps) || applyTo(e);
|
||||
}
|
||||
|
||||
void visit(CondExp *e)
|
||||
{
|
||||
doCond(e->econd) || doCond(e->e1) || doCond(e->e2) || applyTo(e);
|
||||
}
|
||||
};
|
||||
|
||||
bool walkPostorder(Expression *e, StoppableVisitor *v)
|
||||
{
|
||||
PostorderExpressionVisitor pv(v);
|
||||
e->accept(&pv);
|
||||
return v->stop;
|
||||
}
|
189
gcc/d/dmd/apply.d
Normal file
189
gcc/d/dmd/apply.d
Normal file
|
@ -0,0 +1,189 @@
|
|||
/**
|
||||
* A depth-first visitor for expressions.
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/apply.d, _apply.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_apply.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/apply.d
|
||||
*/
|
||||
|
||||
module dmd.apply;
|
||||
|
||||
import dmd.arraytypes;
|
||||
import dmd.dsymbol;
|
||||
import dmd.dsymbolsem;
|
||||
import dmd.dtemplate;
|
||||
import dmd.expression;
|
||||
import dmd.visitor;
|
||||
|
||||
bool walkPostorder(Expression e, StoppableVisitor v)
|
||||
{
|
||||
scope PostorderExpressionVisitor pv = new PostorderExpressionVisitor(v);
|
||||
e.accept(pv);
|
||||
return v.stop;
|
||||
}
|
||||
|
||||
/*********************************
|
||||
* Iterate this dsymbol or members of this scoped dsymbol, then
|
||||
* call `fp` with the found symbol and `params`.
|
||||
* Params:
|
||||
* symbol = the dsymbol or parent of members to call fp on
|
||||
* fp = function pointer to process the iterated symbol.
|
||||
* If it returns nonzero, the iteration will be aborted.
|
||||
* params = any parameters passed to fp.
|
||||
* Returns:
|
||||
* nonzero if the iteration is aborted by the return value of fp,
|
||||
* or 0 if it's completed.
|
||||
*/
|
||||
int apply(FP, Params...)(Dsymbol symbol, FP fp, Params params)
|
||||
{
|
||||
if (auto nd = symbol.isNspace())
|
||||
{
|
||||
return nd.members.foreachDsymbol( (s) { return s && s.apply(fp, params); } );
|
||||
}
|
||||
if (auto ad = symbol.isAttribDeclaration())
|
||||
{
|
||||
return ad.include(ad._scope).foreachDsymbol( (s) { return s && s.apply(fp, params); } );
|
||||
}
|
||||
if (auto tm = symbol.isTemplateMixin())
|
||||
{
|
||||
if (tm._scope) // if fwd reference
|
||||
dsymbolSemantic(tm, null); // try to resolve it
|
||||
|
||||
return tm.members.foreachDsymbol( (s) { return s && s.apply(fp, params); } );
|
||||
}
|
||||
|
||||
return fp(symbol, params);
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* An Expression tree walker that will visit each Expression e in the tree,
|
||||
* in depth-first evaluation order, and call fp(e,param) on it.
|
||||
* fp() signals whether the walking continues with its return value:
|
||||
* Returns:
|
||||
* 0 continue
|
||||
* 1 done
|
||||
* It's a bit slower than using virtual functions, but more encapsulated and less brittle.
|
||||
* Creating an iterator for this would be much more complex.
|
||||
*/
|
||||
private extern (C++) final class PostorderExpressionVisitor : StoppableVisitor
|
||||
{
|
||||
alias visit = typeof(super).visit;
|
||||
public:
|
||||
StoppableVisitor v;
|
||||
|
||||
extern (D) this(StoppableVisitor v)
|
||||
{
|
||||
this.v = v;
|
||||
}
|
||||
|
||||
bool doCond(Expression e)
|
||||
{
|
||||
if (!stop && e)
|
||||
e.accept(this);
|
||||
return stop;
|
||||
}
|
||||
|
||||
bool doCond(Expressions* e)
|
||||
{
|
||||
if (!e)
|
||||
return false;
|
||||
for (size_t i = 0; i < e.dim && !stop; i++)
|
||||
doCond((*e)[i]);
|
||||
return stop;
|
||||
}
|
||||
|
||||
bool applyTo(Expression e)
|
||||
{
|
||||
e.accept(v);
|
||||
stop = v.stop;
|
||||
return true;
|
||||
}
|
||||
|
||||
override void visit(Expression e)
|
||||
{
|
||||
applyTo(e);
|
||||
}
|
||||
|
||||
override void visit(NewExp e)
|
||||
{
|
||||
//printf("NewExp::apply(): %s\n", toChars());
|
||||
doCond(e.thisexp) || doCond(e.newargs) || doCond(e.arguments) || applyTo(e);
|
||||
}
|
||||
|
||||
override void visit(NewAnonClassExp e)
|
||||
{
|
||||
//printf("NewAnonClassExp::apply(): %s\n", toChars());
|
||||
doCond(e.thisexp) || doCond(e.newargs) || doCond(e.arguments) || applyTo(e);
|
||||
}
|
||||
|
||||
override void visit(TypeidExp e)
|
||||
{
|
||||
doCond(isExpression(e.obj)) || applyTo(e);
|
||||
}
|
||||
|
||||
override void visit(UnaExp e)
|
||||
{
|
||||
doCond(e.e1) || applyTo(e);
|
||||
}
|
||||
|
||||
override void visit(BinExp e)
|
||||
{
|
||||
doCond(e.e1) || doCond(e.e2) || applyTo(e);
|
||||
}
|
||||
|
||||
override void visit(AssertExp e)
|
||||
{
|
||||
//printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
|
||||
doCond(e.e1) || doCond(e.msg) || applyTo(e);
|
||||
}
|
||||
|
||||
override void visit(CallExp e)
|
||||
{
|
||||
//printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
|
||||
doCond(e.e1) || doCond(e.arguments) || applyTo(e);
|
||||
}
|
||||
|
||||
override void visit(ArrayExp e)
|
||||
{
|
||||
//printf("ArrayExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
|
||||
doCond(e.e1) || doCond(e.arguments) || applyTo(e);
|
||||
}
|
||||
|
||||
override void visit(SliceExp e)
|
||||
{
|
||||
doCond(e.e1) || doCond(e.lwr) || doCond(e.upr) || applyTo(e);
|
||||
}
|
||||
|
||||
override void visit(ArrayLiteralExp e)
|
||||
{
|
||||
doCond(e.basis) || doCond(e.elements) || applyTo(e);
|
||||
}
|
||||
|
||||
override void visit(AssocArrayLiteralExp e)
|
||||
{
|
||||
doCond(e.keys) || doCond(e.values) || applyTo(e);
|
||||
}
|
||||
|
||||
override void visit(StructLiteralExp e)
|
||||
{
|
||||
if (e.stageflags & stageApply)
|
||||
return;
|
||||
int old = e.stageflags;
|
||||
e.stageflags |= stageApply;
|
||||
doCond(e.elements) || applyTo(e);
|
||||
e.stageflags = old;
|
||||
}
|
||||
|
||||
override void visit(TupleExp e)
|
||||
{
|
||||
doCond(e.e0) || doCond(e.exps) || applyTo(e);
|
||||
}
|
||||
|
||||
override void visit(CondExp e)
|
||||
{
|
||||
doCond(e.econd) || doCond(e.e1) || doCond(e.e2) || applyTo(e);
|
||||
}
|
||||
}
|
|
@ -1,634 +0,0 @@
|
|||
|
||||
/* Compiler implementation of the D programming language
|
||||
* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/D-Programming-Language/dmd/blob/master/src/arrayop.c
|
||||
*/
|
||||
|
||||
#include "root/dsystem.h"
|
||||
#include "root/rmem.h"
|
||||
#include "root/aav.h"
|
||||
|
||||
#include "mars.h"
|
||||
#include "expression.h"
|
||||
#include "statement.h"
|
||||
#include "mtype.h"
|
||||
#include "declaration.h"
|
||||
#include "scope.h"
|
||||
#include "id.h"
|
||||
#include "module.h"
|
||||
#include "init.h"
|
||||
#include "tokens.h"
|
||||
|
||||
void buildArrayIdent(Expression *e, OutBuffer *buf, Expressions *arguments);
|
||||
Expression *buildArrayLoop(Expression *e, Parameters *fparams);
|
||||
|
||||
/**************************************
|
||||
* Hash table of array op functions already generated or known about.
|
||||
*/
|
||||
|
||||
AA *arrayfuncs;
|
||||
|
||||
/**************************************
|
||||
* Structure to contain information needed to insert an array op call
|
||||
*/
|
||||
|
||||
FuncDeclaration *buildArrayOp(Identifier *ident, BinExp *exp, Scope *sc)
|
||||
{
|
||||
Parameters *fparams = new Parameters();
|
||||
Expression *loopbody = buildArrayLoop(exp, fparams);
|
||||
|
||||
/* Construct the function body:
|
||||
* foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++)
|
||||
* loopbody;
|
||||
* return p;
|
||||
*/
|
||||
|
||||
Parameter *p = (*fparams)[0];
|
||||
// foreach (i; 0 .. p.length)
|
||||
Statement *s1 = new ForeachRangeStatement(Loc(), TOKforeach,
|
||||
new Parameter(0, NULL, Id::p, NULL, NULL),
|
||||
new IntegerExp(Loc(), 0, Type::tsize_t),
|
||||
new ArrayLengthExp(Loc(), new IdentifierExp(Loc(), p->ident)),
|
||||
new ExpStatement(Loc(), loopbody),
|
||||
Loc());
|
||||
//printf("%s\n", s1->toChars());
|
||||
Statement *s2 = new ReturnStatement(Loc(), new IdentifierExp(Loc(), p->ident));
|
||||
//printf("s2: %s\n", s2->toChars());
|
||||
Statement *fbody = new CompoundStatement(Loc(), s1, s2);
|
||||
|
||||
// Built-in array ops should be @trusted, pure, nothrow and nogc
|
||||
StorageClass stc = STCtrusted | STCpure | STCnothrow | STCnogc;
|
||||
|
||||
/* Construct the function
|
||||
*/
|
||||
TypeFunction *ftype = new TypeFunction(ParameterList(fparams), exp->e1->type, LINKc, stc);
|
||||
//printf("fd: %s %s\n", ident->toChars(), ftype->toChars());
|
||||
FuncDeclaration *fd = new FuncDeclaration(Loc(), Loc(), ident, STCundefined, ftype);
|
||||
fd->fbody = fbody;
|
||||
fd->protection = Prot(Prot::public_);
|
||||
fd->linkage = LINKc;
|
||||
fd->isArrayOp = 1;
|
||||
|
||||
sc->_module->importedFrom->members->push(fd);
|
||||
|
||||
sc = sc->push();
|
||||
sc->parent = sc->_module->importedFrom;
|
||||
sc->stc = 0;
|
||||
sc->linkage = LINKc;
|
||||
dsymbolSemantic(fd, sc);
|
||||
semantic2(fd, sc);
|
||||
unsigned errors = global.startGagging();
|
||||
semantic3(fd, sc);
|
||||
if (global.endGagging(errors))
|
||||
{
|
||||
fd->type = Type::terror;
|
||||
fd->errors = true;
|
||||
fd->fbody = NULL;
|
||||
}
|
||||
sc->pop();
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
* Check that there are no uses of arrays without [].
|
||||
*/
|
||||
bool isArrayOpValid(Expression *e)
|
||||
{
|
||||
if (e->op == TOKslice)
|
||||
return true;
|
||||
if (e->op == TOKarrayliteral)
|
||||
{
|
||||
Type *t = e->type->toBasetype();
|
||||
while (t->ty == Tarray || t->ty == Tsarray)
|
||||
t = t->nextOf()->toBasetype();
|
||||
return (t->ty != Tvoid);
|
||||
}
|
||||
Type *tb = e->type->toBasetype();
|
||||
if (tb->ty == Tarray || tb->ty == Tsarray)
|
||||
{
|
||||
if (isUnaArrayOp(e->op))
|
||||
{
|
||||
return isArrayOpValid(((UnaExp *)e)->e1);
|
||||
}
|
||||
if (isBinArrayOp(e->op) ||
|
||||
isBinAssignArrayOp(e->op) ||
|
||||
e->op == TOKassign)
|
||||
{
|
||||
BinExp *be = (BinExp *)e;
|
||||
return isArrayOpValid(be->e1) && isArrayOpValid(be->e2);
|
||||
}
|
||||
if (e->op == TOKconstruct)
|
||||
{
|
||||
BinExp *be = (BinExp *)e;
|
||||
return be->e1->op == TOKslice && isArrayOpValid(be->e2);
|
||||
}
|
||||
if (e->op == TOKcall)
|
||||
{
|
||||
return false; // TODO: Decide if [] is required after arrayop calls.
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isNonAssignmentArrayOp(Expression *e)
|
||||
{
|
||||
if (e->op == TOKslice)
|
||||
return isNonAssignmentArrayOp(((SliceExp *)e)->e1);
|
||||
|
||||
Type *tb = e->type->toBasetype();
|
||||
if (tb->ty == Tarray || tb->ty == Tsarray)
|
||||
{
|
||||
return (isUnaArrayOp(e->op) || isBinArrayOp(e->op));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool checkNonAssignmentArrayOp(Expression *e, bool suggestion)
|
||||
{
|
||||
if (isNonAssignmentArrayOp(e))
|
||||
{
|
||||
const char *s = "";
|
||||
if (suggestion)
|
||||
s = " (possible missing [])";
|
||||
e->error("array operation %s without destination memory not allowed%s", e->toChars(), s);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/***********************************
|
||||
* Construct the array operation expression.
|
||||
*/
|
||||
|
||||
Expression *arrayOp(BinExp *e, Scope *sc)
|
||||
{
|
||||
//printf("BinExp::arrayOp() %s\n", toChars());
|
||||
|
||||
Type *tb = e->type->toBasetype();
|
||||
assert(tb->ty == Tarray || tb->ty == Tsarray);
|
||||
Type *tbn = tb->nextOf()->toBasetype();
|
||||
if (tbn->ty == Tvoid)
|
||||
{
|
||||
e->error("cannot perform array operations on void[] arrays");
|
||||
return new ErrorExp();
|
||||
}
|
||||
if (!isArrayOpValid(e))
|
||||
{
|
||||
e->error("invalid array operation %s (possible missing [])", e->toChars());
|
||||
return new ErrorExp();
|
||||
}
|
||||
|
||||
Expressions *arguments = new Expressions();
|
||||
|
||||
/* The expression to generate an array operation for is mangled
|
||||
* into a name to use as the array operation function name.
|
||||
* Mangle in the operands and operators in RPN order, and type.
|
||||
*/
|
||||
OutBuffer buf;
|
||||
buf.writestring("_array");
|
||||
buildArrayIdent(e, &buf, arguments);
|
||||
buf.writeByte('_');
|
||||
|
||||
/* Append deco of array element type
|
||||
*/
|
||||
buf.writestring(e->type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco);
|
||||
|
||||
char *name = buf.peekChars();
|
||||
Identifier *ident = Identifier::idPool(name);
|
||||
|
||||
FuncDeclaration **pFd = (FuncDeclaration **)dmd_aaGet(&arrayfuncs, (void *)ident);
|
||||
FuncDeclaration *fd = *pFd;
|
||||
|
||||
if (!fd)
|
||||
fd = buildArrayOp(ident, e, sc);
|
||||
|
||||
if (fd && fd->errors)
|
||||
{
|
||||
const char *fmt;
|
||||
if (tbn->ty == Tstruct || tbn->ty == Tclass)
|
||||
fmt = "invalid array operation '%s' because %s doesn't support necessary arithmetic operations";
|
||||
else if (!tbn->isscalar())
|
||||
fmt = "invalid array operation '%s' because %s is not a scalar type";
|
||||
else
|
||||
fmt = "invalid array operation '%s' for element type %s";
|
||||
|
||||
e->error(fmt, e->toChars(), tbn->toChars());
|
||||
return new ErrorExp();
|
||||
}
|
||||
|
||||
*pFd = fd;
|
||||
|
||||
Expression *ev = new VarExp(e->loc, fd);
|
||||
Expression *ec = new CallExp(e->loc, ev, arguments);
|
||||
|
||||
return expressionSemantic(ec, sc);
|
||||
}
|
||||
|
||||
Expression *arrayOp(BinAssignExp *e, Scope *sc)
|
||||
{
|
||||
//printf("BinAssignExp::arrayOp() %s\n", toChars());
|
||||
|
||||
/* Check that the elements of e1 can be assigned to
|
||||
*/
|
||||
Type *tn = e->e1->type->toBasetype()->nextOf();
|
||||
|
||||
if (tn && (!tn->isMutable() || !tn->isAssignable()))
|
||||
{
|
||||
e->error("slice %s is not mutable", e->e1->toChars());
|
||||
return new ErrorExp();
|
||||
}
|
||||
if (e->e1->op == TOKarrayliteral)
|
||||
{
|
||||
return e->e1->modifiableLvalue(sc, e->e1);
|
||||
}
|
||||
|
||||
return arrayOp((BinExp *)e, sc);
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Construct the identifier for the array operation function,
|
||||
* and build the argument list to pass to it.
|
||||
*/
|
||||
|
||||
void buildArrayIdent(Expression *e, OutBuffer *buf, Expressions *arguments)
|
||||
{
|
||||
class BuildArrayIdentVisitor : public Visitor
|
||||
{
|
||||
OutBuffer *buf;
|
||||
Expressions *arguments;
|
||||
public:
|
||||
BuildArrayIdentVisitor(OutBuffer *buf, Expressions *arguments)
|
||||
: buf(buf), arguments(arguments)
|
||||
{
|
||||
}
|
||||
|
||||
void visit(Expression *e)
|
||||
{
|
||||
buf->writestring("Exp");
|
||||
arguments->shift(e);
|
||||
}
|
||||
|
||||
void visit(CastExp *e)
|
||||
{
|
||||
Type *tb = e->type->toBasetype();
|
||||
if (tb->ty == Tarray || tb->ty == Tsarray)
|
||||
{
|
||||
e->e1->accept(this);
|
||||
}
|
||||
else
|
||||
visit((Expression *)e);
|
||||
}
|
||||
|
||||
void visit(ArrayLiteralExp *e)
|
||||
{
|
||||
buf->writestring("Slice");
|
||||
arguments->shift(e);
|
||||
}
|
||||
|
||||
void visit(SliceExp *e)
|
||||
{
|
||||
buf->writestring("Slice");
|
||||
arguments->shift(e);
|
||||
}
|
||||
|
||||
void visit(AssignExp *e)
|
||||
{
|
||||
/* Evaluate assign expressions right to left
|
||||
*/
|
||||
e->e2->accept(this);
|
||||
e->e1->accept(this);
|
||||
buf->writestring("Assign");
|
||||
}
|
||||
|
||||
void visit(BinAssignExp *e)
|
||||
{
|
||||
/* Evaluate assign expressions right to left
|
||||
*/
|
||||
e->e2->accept(this);
|
||||
e->e1->accept(this);
|
||||
const char *s;
|
||||
switch(e->op)
|
||||
{
|
||||
case TOKaddass: s = "Addass"; break;
|
||||
case TOKminass: s = "Minass"; break;
|
||||
case TOKmulass: s = "Mulass"; break;
|
||||
case TOKdivass: s = "Divass"; break;
|
||||
case TOKmodass: s = "Modass"; break;
|
||||
case TOKxorass: s = "Xorass"; break;
|
||||
case TOKandass: s = "Andass"; break;
|
||||
case TOKorass: s = "Orass"; break;
|
||||
case TOKpowass: s = "Powass"; break;
|
||||
default: assert(0);
|
||||
}
|
||||
buf->writestring(s);
|
||||
}
|
||||
|
||||
void visit(NegExp *e)
|
||||
{
|
||||
e->e1->accept(this);
|
||||
buf->writestring("Neg");
|
||||
}
|
||||
|
||||
void visit(ComExp *e)
|
||||
{
|
||||
e->e1->accept(this);
|
||||
buf->writestring("Com");
|
||||
}
|
||||
|
||||
void visit(BinExp *e)
|
||||
{
|
||||
/* Evaluate assign expressions left to right
|
||||
*/
|
||||
const char *s = NULL;
|
||||
switch(e->op)
|
||||
{
|
||||
case TOKadd: s = "Add"; break;
|
||||
case TOKmin: s = "Min"; break;
|
||||
case TOKmul: s = "Mul"; break;
|
||||
case TOKdiv: s = "Div"; break;
|
||||
case TOKmod: s = "Mod"; break;
|
||||
case TOKxor: s = "Xor"; break;
|
||||
case TOKand: s = "And"; break;
|
||||
case TOKor: s = "Or"; break;
|
||||
case TOKpow: s = "Pow"; break;
|
||||
default: break;
|
||||
}
|
||||
if (s)
|
||||
{
|
||||
Type *tb = e->type->toBasetype();
|
||||
Type *t1 = e->e1->type->toBasetype();
|
||||
Type *t2 = e->e2->type->toBasetype();
|
||||
e->e1->accept(this);
|
||||
if (t1->ty == Tarray &&
|
||||
((t2->ty == Tarray && !t1->equivalent(tb)) ||
|
||||
(t2->ty != Tarray && !t1->nextOf()->equivalent(e->e2->type))))
|
||||
{
|
||||
// Bugzilla 12780: if A is narrower than B
|
||||
// A[] op B[]
|
||||
// A[] op B
|
||||
buf->writestring("Of");
|
||||
buf->writestring(t1->nextOf()->mutableOf()->deco);
|
||||
}
|
||||
e->e2->accept(this);
|
||||
if (t2->ty == Tarray &&
|
||||
((t1->ty == Tarray && !t2->equivalent(tb)) ||
|
||||
(t1->ty != Tarray && !t2->nextOf()->equivalent(e->e1->type))))
|
||||
{
|
||||
// Bugzilla 12780: if B is narrower than A:
|
||||
// A[] op B[]
|
||||
// A op B[]
|
||||
buf->writestring("Of");
|
||||
buf->writestring(t2->nextOf()->mutableOf()->deco);
|
||||
}
|
||||
buf->writestring(s);
|
||||
}
|
||||
else
|
||||
visit((Expression *)e);
|
||||
}
|
||||
};
|
||||
|
||||
BuildArrayIdentVisitor v(buf, arguments);
|
||||
e->accept(&v);
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Construct the inner loop for the array operation function,
|
||||
* and build the parameter list.
|
||||
*/
|
||||
|
||||
Expression *buildArrayLoop(Expression *e, Parameters *fparams)
|
||||
{
|
||||
class BuildArrayLoopVisitor : public Visitor
|
||||
{
|
||||
Parameters *fparams;
|
||||
Expression *result;
|
||||
|
||||
public:
|
||||
BuildArrayLoopVisitor(Parameters *fparams)
|
||||
: fparams(fparams), result(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void visit(Expression *e)
|
||||
{
|
||||
Identifier *id = Identifier::generateId("c", fparams->length);
|
||||
Parameter *param = new Parameter(0, e->type, id, NULL, NULL);
|
||||
fparams->shift(param);
|
||||
result = new IdentifierExp(Loc(), id);
|
||||
}
|
||||
|
||||
void visit(CastExp *e)
|
||||
{
|
||||
Type *tb = e->type->toBasetype();
|
||||
if (tb->ty == Tarray || tb->ty == Tsarray)
|
||||
{
|
||||
e->e1->accept(this);
|
||||
}
|
||||
else
|
||||
visit((Expression *)e);
|
||||
}
|
||||
|
||||
void visit(ArrayLiteralExp *e)
|
||||
{
|
||||
Identifier *id = Identifier::generateId("p", fparams->length);
|
||||
Parameter *param = new Parameter(STCconst, e->type, id, NULL, NULL);
|
||||
fparams->shift(param);
|
||||
Expression *ie = new IdentifierExp(Loc(), id);
|
||||
Expression *index = new IdentifierExp(Loc(), Id::p);
|
||||
result = new ArrayExp(Loc(), ie, index);
|
||||
}
|
||||
|
||||
void visit(SliceExp *e)
|
||||
{
|
||||
Identifier *id = Identifier::generateId("p", fparams->length);
|
||||
Parameter *param = new Parameter(STCconst, e->type, id, NULL, NULL);
|
||||
fparams->shift(param);
|
||||
Expression *ie = new IdentifierExp(Loc(), id);
|
||||
Expression *index = new IdentifierExp(Loc(), Id::p);
|
||||
result = new ArrayExp(Loc(), ie, index);
|
||||
}
|
||||
|
||||
void visit(AssignExp *e)
|
||||
{
|
||||
/* Evaluate assign expressions right to left
|
||||
*/
|
||||
Expression *ex2 = buildArrayLoop(e->e2);
|
||||
/* Need the cast because:
|
||||
* b = c + p[i];
|
||||
* where b is a byte fails because (c + p[i]) is an int
|
||||
* which cannot be implicitly cast to byte.
|
||||
*/
|
||||
ex2 = new CastExp(Loc(), ex2, e->e1->type->nextOf());
|
||||
Expression *ex1 = buildArrayLoop(e->e1);
|
||||
Parameter *param = (*fparams)[0];
|
||||
param->storageClass = 0;
|
||||
result = new AssignExp(Loc(), ex1, ex2);
|
||||
}
|
||||
|
||||
void visit(BinAssignExp *e)
|
||||
{
|
||||
/* Evaluate assign expressions right to left
|
||||
*/
|
||||
Expression *ex2 = buildArrayLoop(e->e2);
|
||||
Expression *ex1 = buildArrayLoop(e->e1);
|
||||
Parameter *param = (*fparams)[0];
|
||||
param->storageClass = 0;
|
||||
switch(e->op)
|
||||
{
|
||||
case TOKaddass: result = new AddAssignExp(e->loc, ex1, ex2); return;
|
||||
case TOKminass: result = new MinAssignExp(e->loc, ex1, ex2); return;
|
||||
case TOKmulass: result = new MulAssignExp(e->loc, ex1, ex2); return;
|
||||
case TOKdivass: result = new DivAssignExp(e->loc, ex1, ex2); return;
|
||||
case TOKmodass: result = new ModAssignExp(e->loc, ex1, ex2); return;
|
||||
case TOKxorass: result = new XorAssignExp(e->loc, ex1, ex2); return;
|
||||
case TOKandass: result = new AndAssignExp(e->loc, ex1, ex2); return;
|
||||
case TOKorass: result = new OrAssignExp(e->loc, ex1, ex2); return;
|
||||
case TOKpowass: result = new PowAssignExp(e->loc, ex1, ex2); return;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void visit(NegExp *e)
|
||||
{
|
||||
Expression *ex1 = buildArrayLoop(e->e1);
|
||||
result = new NegExp(Loc(), ex1);
|
||||
}
|
||||
|
||||
void visit(ComExp *e)
|
||||
{
|
||||
Expression *ex1 = buildArrayLoop(e->e1);
|
||||
result = new ComExp(Loc(), ex1);
|
||||
}
|
||||
|
||||
void visit(BinExp *e)
|
||||
{
|
||||
if (isBinArrayOp(e->op))
|
||||
{
|
||||
/* Evaluate assign expressions left to right
|
||||
*/
|
||||
BinExp *be = (BinExp *)e->copy();
|
||||
be->e1 = buildArrayLoop(be->e1);
|
||||
be->e2 = buildArrayLoop(be->e2);
|
||||
be->type = NULL;
|
||||
result = be;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
visit((Expression *)e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Expression *buildArrayLoop(Expression *e)
|
||||
{
|
||||
e->accept(this);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
BuildArrayLoopVisitor v(fparams);
|
||||
return v.buildArrayLoop(e);
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Test if expression is a unary array op.
|
||||
*/
|
||||
|
||||
bool isUnaArrayOp(TOK op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case TOKneg:
|
||||
case TOKtilde:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Test if expression is a binary array op.
|
||||
*/
|
||||
|
||||
bool isBinArrayOp(TOK op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case TOKadd:
|
||||
case TOKmin:
|
||||
case TOKmul:
|
||||
case TOKdiv:
|
||||
case TOKmod:
|
||||
case TOKxor:
|
||||
case TOKand:
|
||||
case TOKor:
|
||||
case TOKpow:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Test if expression is a binary assignment array op.
|
||||
*/
|
||||
|
||||
bool isBinAssignArrayOp(TOK op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case TOKaddass:
|
||||
case TOKminass:
|
||||
case TOKmulass:
|
||||
case TOKdivass:
|
||||
case TOKmodass:
|
||||
case TOKxorass:
|
||||
case TOKandass:
|
||||
case TOKorass:
|
||||
case TOKpowass:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Test if operand is a valid array op operand.
|
||||
*/
|
||||
|
||||
bool isArrayOpOperand(Expression *e)
|
||||
{
|
||||
//printf("Expression::isArrayOpOperand() %s\n", e->toChars());
|
||||
if (e->op == TOKslice)
|
||||
return true;
|
||||
if (e->op == TOKarrayliteral)
|
||||
{
|
||||
Type *t = e->type->toBasetype();
|
||||
while (t->ty == Tarray || t->ty == Tsarray)
|
||||
t = t->nextOf()->toBasetype();
|
||||
return (t->ty != Tvoid);
|
||||
}
|
||||
Type *tb = e->type->toBasetype();
|
||||
if (tb->ty == Tarray)
|
||||
{
|
||||
return (isUnaArrayOp(e->op) ||
|
||||
isBinArrayOp(e->op) ||
|
||||
isBinAssignArrayOp(e->op) ||
|
||||
e->op == TOKassign);
|
||||
}
|
||||
return false;
|
||||
}
|
387
gcc/d/dmd/arrayop.d
Normal file
387
gcc/d/dmd/arrayop.d
Normal file
|
@ -0,0 +1,387 @@
|
|||
/**
|
||||
* Implement array operations, such as `a[] = b[] + c[]`.
|
||||
*
|
||||
* Specification: $(LINK2 https://dlang.org/spec/arrays.html#array-operations, Array Operations)
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arrayop.d, _arrayop.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_arrayop.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/arrayop.d
|
||||
*/
|
||||
|
||||
module dmd.arrayop;
|
||||
|
||||
import core.stdc.stdio;
|
||||
import dmd.arraytypes;
|
||||
import dmd.astenums;
|
||||
import dmd.declaration;
|
||||
import dmd.dscope;
|
||||
import dmd.dsymbol;
|
||||
import dmd.expression;
|
||||
import dmd.expressionsem;
|
||||
import dmd.func;
|
||||
import dmd.globals;
|
||||
import dmd.id;
|
||||
import dmd.identifier;
|
||||
import dmd.mtype;
|
||||
import dmd.root.outbuffer;
|
||||
import dmd.statement;
|
||||
import dmd.tokens;
|
||||
import dmd.visitor;
|
||||
|
||||
/**********************************************
|
||||
* Check that there are no uses of arrays without [].
|
||||
*/
|
||||
bool isArrayOpValid(Expression e)
|
||||
{
|
||||
//printf("isArrayOpValid() %s\n", e.toChars());
|
||||
if (e.op == TOK.slice)
|
||||
return true;
|
||||
if (e.op == TOK.arrayLiteral)
|
||||
{
|
||||
Type t = e.type.toBasetype();
|
||||
while (t.ty == Tarray || t.ty == Tsarray)
|
||||
t = t.nextOf().toBasetype();
|
||||
return (t.ty != Tvoid);
|
||||
}
|
||||
Type tb = e.type.toBasetype();
|
||||
if (tb.ty == Tarray || tb.ty == Tsarray)
|
||||
{
|
||||
if (isUnaArrayOp(e.op))
|
||||
{
|
||||
return isArrayOpValid((cast(UnaExp)e).e1);
|
||||
}
|
||||
if (isBinArrayOp(e.op) || isBinAssignArrayOp(e.op) || e.op == TOK.assign)
|
||||
{
|
||||
BinExp be = cast(BinExp)e;
|
||||
return isArrayOpValid(be.e1) && isArrayOpValid(be.e2);
|
||||
}
|
||||
if (e.op == TOK.construct)
|
||||
{
|
||||
BinExp be = cast(BinExp)e;
|
||||
return be.e1.op == TOK.slice && isArrayOpValid(be.e2);
|
||||
}
|
||||
// if (e.op == TOK.call)
|
||||
// {
|
||||
// TODO: Decide if [] is required after arrayop calls.
|
||||
// }
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isNonAssignmentArrayOp(Expression e)
|
||||
{
|
||||
if (e.op == TOK.slice)
|
||||
return isNonAssignmentArrayOp((cast(SliceExp)e).e1);
|
||||
|
||||
Type tb = e.type.toBasetype();
|
||||
if (tb.ty == Tarray || tb.ty == Tsarray)
|
||||
{
|
||||
return (isUnaArrayOp(e.op) || isBinArrayOp(e.op));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool checkNonAssignmentArrayOp(Expression e, bool suggestion = false)
|
||||
{
|
||||
if (isNonAssignmentArrayOp(e))
|
||||
{
|
||||
const(char)* s = "";
|
||||
if (suggestion)
|
||||
s = " (possible missing [])";
|
||||
e.error("array operation `%s` without destination memory not allowed%s", e.toChars(), s);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/***********************************
|
||||
* Construct the array operation expression, call object._arrayOp!(tiargs)(args).
|
||||
*
|
||||
* Encode operand types and operations into tiargs using reverse polish notation (RPN) to preserve precedence.
|
||||
* Unary operations are prefixed with "u" (e.g. "u~").
|
||||
* Pass operand values (slices or scalars) as args.
|
||||
*
|
||||
* Scalar expression sub-trees of `e` are evaluated before calling
|
||||
* into druntime to hoist them out of the loop. This is a valid
|
||||
* evaluation order as the actual array operations have no
|
||||
* side-effect.
|
||||
* References:
|
||||
* https://github.com/dlang/druntime/blob/master/src/object.d#L3944
|
||||
* https://github.com/dlang/druntime/blob/master/src/core/internal/array/operations.d
|
||||
*/
|
||||
Expression arrayOp(BinExp e, Scope* sc)
|
||||
{
|
||||
//printf("BinExp.arrayOp() %s\n", e.toChars());
|
||||
Type tb = e.type.toBasetype();
|
||||
assert(tb.ty == Tarray || tb.ty == Tsarray);
|
||||
Type tbn = tb.nextOf().toBasetype();
|
||||
if (tbn.ty == Tvoid)
|
||||
{
|
||||
e.error("cannot perform array operations on `void[]` arrays");
|
||||
return ErrorExp.get();
|
||||
}
|
||||
if (!isArrayOpValid(e))
|
||||
return arrayOpInvalidError(e);
|
||||
|
||||
auto tiargs = new Objects();
|
||||
auto args = new Expressions();
|
||||
buildArrayOp(sc, e, tiargs, args);
|
||||
|
||||
import dmd.dtemplate : TemplateDeclaration;
|
||||
__gshared TemplateDeclaration arrayOp;
|
||||
if (arrayOp is null)
|
||||
{
|
||||
// Create .object._arrayOp
|
||||
Identifier idArrayOp = Identifier.idPool("_arrayOp");
|
||||
Expression id = new IdentifierExp(e.loc, Id.empty);
|
||||
id = new DotIdExp(e.loc, id, Id.object);
|
||||
id = new DotIdExp(e.loc, id, idArrayOp);
|
||||
|
||||
id = id.expressionSemantic(sc);
|
||||
if (auto te = id.isTemplateExp())
|
||||
arrayOp = te.td;
|
||||
else
|
||||
ObjectNotFound(idArrayOp); // fatal error
|
||||
}
|
||||
|
||||
auto fd = resolveFuncCall(e.loc, sc, arrayOp, tiargs, null, args, FuncResolveFlag.standard);
|
||||
if (!fd || fd.errors)
|
||||
return ErrorExp.get();
|
||||
return new CallExp(e.loc, new VarExp(e.loc, fd, false), args).expressionSemantic(sc);
|
||||
}
|
||||
|
||||
/// ditto
|
||||
Expression arrayOp(BinAssignExp e, Scope* sc)
|
||||
{
|
||||
//printf("BinAssignExp.arrayOp() %s\n", toChars());
|
||||
|
||||
/* Check that the elements of e1 can be assigned to
|
||||
*/
|
||||
Type tn = e.e1.type.toBasetype().nextOf();
|
||||
|
||||
if (tn && (!tn.isMutable() || !tn.isAssignable()))
|
||||
{
|
||||
e.error("slice `%s` is not mutable", e.e1.toChars());
|
||||
if (e.op == TOK.addAssign)
|
||||
checkPossibleAddCatError!(AddAssignExp, CatAssignExp)(e.isAddAssignExp);
|
||||
return ErrorExp.get();
|
||||
}
|
||||
if (e.e1.op == TOK.arrayLiteral)
|
||||
{
|
||||
return e.e1.modifiableLvalue(sc, e.e1);
|
||||
}
|
||||
|
||||
return arrayOp(cast(BinExp)e, sc);
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Convert the expression tree e to template and function arguments,
|
||||
* using reverse polish notation (RPN) to encode order of operations.
|
||||
* Encode operations as string arguments, using a "u" prefix for unary operations.
|
||||
*/
|
||||
private void buildArrayOp(Scope* sc, Expression e, Objects* tiargs, Expressions* args)
|
||||
{
|
||||
extern (C++) final class BuildArrayOpVisitor : Visitor
|
||||
{
|
||||
alias visit = Visitor.visit;
|
||||
Scope* sc;
|
||||
Objects* tiargs;
|
||||
Expressions* args;
|
||||
|
||||
public:
|
||||
extern (D) this(Scope* sc, Objects* tiargs, Expressions* args)
|
||||
{
|
||||
this.sc = sc;
|
||||
this.tiargs = tiargs;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
override void visit(Expression e)
|
||||
{
|
||||
tiargs.push(e.type);
|
||||
args.push(e);
|
||||
}
|
||||
|
||||
override void visit(SliceExp e)
|
||||
{
|
||||
visit(cast(Expression) e);
|
||||
}
|
||||
|
||||
override void visit(CastExp e)
|
||||
{
|
||||
visit(cast(Expression) e);
|
||||
}
|
||||
|
||||
override void visit(UnaExp e)
|
||||
{
|
||||
Type tb = e.type.toBasetype();
|
||||
if (tb.ty != Tarray && tb.ty != Tsarray) // hoist scalar expressions
|
||||
{
|
||||
visit(cast(Expression) e);
|
||||
}
|
||||
else
|
||||
{
|
||||
// RPN, prefix unary ops with u
|
||||
OutBuffer buf;
|
||||
buf.writestring("u");
|
||||
buf.writestring(Token.toString(e.op));
|
||||
e.e1.accept(this);
|
||||
tiargs.push(new StringExp(Loc.initial, buf.extractSlice()).expressionSemantic(sc));
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(BinExp e)
|
||||
{
|
||||
Type tb = e.type.toBasetype();
|
||||
if (tb.ty != Tarray && tb.ty != Tsarray) // hoist scalar expressions
|
||||
{
|
||||
visit(cast(Expression) e);
|
||||
}
|
||||
else
|
||||
{
|
||||
// RPN
|
||||
e.e1.accept(this);
|
||||
e.e2.accept(this);
|
||||
tiargs.push(new StringExp(Loc.initial, Token.toString(e.op)).expressionSemantic(sc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope v = new BuildArrayOpVisitor(sc, tiargs, args);
|
||||
e.accept(v);
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Some implicit casting can be performed by the _arrayOp template.
|
||||
* Params:
|
||||
* tfrom = type converting from
|
||||
* tto = type converting to
|
||||
* Returns:
|
||||
* true if can be performed by _arrayOp
|
||||
*/
|
||||
bool isArrayOpImplicitCast(TypeDArray tfrom, TypeDArray tto)
|
||||
{
|
||||
const tyf = tfrom.nextOf().toBasetype().ty;
|
||||
const tyt = tto .nextOf().toBasetype().ty;
|
||||
return tyf == tyt ||
|
||||
tyf == Tint32 && tyt == Tfloat64;
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Test if expression is a unary array op.
|
||||
*/
|
||||
bool isUnaArrayOp(TOK op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case TOK.negate:
|
||||
case TOK.tilde:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Test if expression is a binary array op.
|
||||
*/
|
||||
bool isBinArrayOp(TOK op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case TOK.add:
|
||||
case TOK.min:
|
||||
case TOK.mul:
|
||||
case TOK.div:
|
||||
case TOK.mod:
|
||||
case TOK.xor:
|
||||
case TOK.and:
|
||||
case TOK.or:
|
||||
case TOK.pow:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Test if expression is a binary assignment array op.
|
||||
*/
|
||||
bool isBinAssignArrayOp(TOK op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case TOK.addAssign:
|
||||
case TOK.minAssign:
|
||||
case TOK.mulAssign:
|
||||
case TOK.divAssign:
|
||||
case TOK.modAssign:
|
||||
case TOK.xorAssign:
|
||||
case TOK.andAssign:
|
||||
case TOK.orAssign:
|
||||
case TOK.powAssign:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Test if operand is a valid array op operand.
|
||||
*/
|
||||
bool isArrayOpOperand(Expression e)
|
||||
{
|
||||
//printf("Expression.isArrayOpOperand() %s\n", e.toChars());
|
||||
if (e.op == TOK.slice)
|
||||
return true;
|
||||
if (e.op == TOK.arrayLiteral)
|
||||
{
|
||||
Type t = e.type.toBasetype();
|
||||
while (t.ty == Tarray || t.ty == Tsarray)
|
||||
t = t.nextOf().toBasetype();
|
||||
return (t.ty != Tvoid);
|
||||
}
|
||||
Type tb = e.type.toBasetype();
|
||||
if (tb.ty == Tarray)
|
||||
{
|
||||
return (isUnaArrayOp(e.op) ||
|
||||
isBinArrayOp(e.op) ||
|
||||
isBinAssignArrayOp(e.op) ||
|
||||
e.op == TOK.assign);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************
|
||||
* Print error message about invalid array operation.
|
||||
* Params:
|
||||
* e = expression with the invalid array operation
|
||||
* Returns:
|
||||
* instance of ErrorExp
|
||||
*/
|
||||
|
||||
ErrorExp arrayOpInvalidError(Expression e)
|
||||
{
|
||||
e.error("invalid array operation `%s` (possible missing [])", e.toChars());
|
||||
if (e.op == TOK.add)
|
||||
checkPossibleAddCatError!(AddExp, CatExp)(e.isAddExp());
|
||||
else if (e.op == TOK.addAssign)
|
||||
checkPossibleAddCatError!(AddAssignExp, CatAssignExp)(e.isAddAssignExp());
|
||||
return ErrorExp.get();
|
||||
}
|
||||
|
||||
private void checkPossibleAddCatError(AddT, CatT)(AddT ae)
|
||||
{
|
||||
if (!ae.e2.type || ae.e2.type.ty != Tarray || !ae.e2.type.implicitConvTo(ae.e1.type))
|
||||
return;
|
||||
CatT ce = new CatT(ae.loc, ae.e1, ae.e2);
|
||||
ae.errorSupplemental("did you mean to concatenate (`%s`) instead ?", ce.toChars());
|
||||
}
|
57
gcc/d/dmd/arraytypes.d
Normal file
57
gcc/d/dmd/arraytypes.d
Normal file
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Provide aliases for arrays of certain declarations or statements.
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arraytypes.d, _arraytypes.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_arraytypes.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/arraytypes.d
|
||||
*/
|
||||
|
||||
module dmd.arraytypes;
|
||||
|
||||
import dmd.dclass;
|
||||
import dmd.declaration;
|
||||
import dmd.dmodule;
|
||||
import dmd.dsymbol;
|
||||
import dmd.dtemplate;
|
||||
import dmd.expression;
|
||||
import dmd.func;
|
||||
import dmd.identifier;
|
||||
import dmd.init;
|
||||
import dmd.mtype;
|
||||
import dmd.root.array;
|
||||
import dmd.root.rootobject;
|
||||
import dmd.statement;
|
||||
|
||||
alias Strings = Array!(const(char)*);
|
||||
alias Identifiers = Array!(Identifier);
|
||||
alias TemplateParameters = Array!(TemplateParameter);
|
||||
alias Expressions = Array!(Expression);
|
||||
alias Statements = Array!(Statement);
|
||||
alias BaseClasses = Array!(BaseClass*);
|
||||
alias ClassDeclarations = Array!(ClassDeclaration);
|
||||
alias Dsymbols = Array!(Dsymbol);
|
||||
alias Objects = Array!(RootObject);
|
||||
alias DtorDeclarations = Array!(DtorDeclaration);
|
||||
alias FuncDeclarations = Array!(FuncDeclaration);
|
||||
alias Parameters = Array!(Parameter);
|
||||
alias Initializers = Array!(Initializer);
|
||||
alias VarDeclarations = Array!(VarDeclaration);
|
||||
alias Types = Array!(Type);
|
||||
alias Catches = Array!(Catch);
|
||||
alias StaticDtorDeclarations = Array!(StaticDtorDeclaration);
|
||||
alias SharedStaticDtorDeclarations = Array!(SharedStaticDtorDeclaration);
|
||||
alias AliasDeclarations = Array!(AliasDeclaration);
|
||||
alias Modules = Array!(Module);
|
||||
alias CaseStatements = Array!(CaseStatement);
|
||||
alias ScopeStatements = Array!(ScopeStatement);
|
||||
alias GotoCaseStatements = Array!(GotoCaseStatement);
|
||||
alias ReturnStatements = Array!(ReturnStatement);
|
||||
alias GotoStatements = Array!(GotoStatement);
|
||||
alias TemplateInstances = Array!(TemplateInstance);
|
||||
alias Ensures = Array!(Ensure);
|
||||
alias Designators = Array!(Designator);
|
||||
alias DesigInits = Array!(DesigInit);
|
||||
|
|
@ -27,6 +27,8 @@ typedef Array<class Dsymbol *> Dsymbols;
|
|||
|
||||
typedef Array<class RootObject *> Objects;
|
||||
|
||||
typedef Array<class DtorDeclaration *> DtorDeclarations;
|
||||
|
||||
typedef Array<class FuncDeclaration *> FuncDeclarations;
|
||||
|
||||
typedef Array<class Parameter *> Parameters;
|
||||
|
@ -48,8 +50,6 @@ typedef Array<class AliasDeclaration *> AliasDeclarations;
|
|||
|
||||
typedef Array<class Module *> Modules;
|
||||
|
||||
typedef Array<struct File *> Files;
|
||||
|
||||
typedef Array<class CaseStatement *> CaseStatements;
|
||||
|
||||
typedef Array<class ScopeStatement *> ScopeStatements;
|
||||
|
@ -63,3 +63,8 @@ typedef Array<class GotoStatement *> GotoStatements;
|
|||
typedef Array<class TemplateInstance *> TemplateInstances;
|
||||
|
||||
typedef Array<struct Ensure> Ensures;
|
||||
|
||||
typedef Array<struct Designator> Designators;
|
||||
|
||||
typedef Array<struct DesigInit> DesigInits;
|
||||
|
||||
|
|
26
gcc/d/dmd/ast_node.d
Normal file
26
gcc/d/dmd/ast_node.d
Normal file
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* Defines the base class for all nodes which are part of the AST.
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ast_node.d, _ast_node.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_ast_node.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ast_node.d
|
||||
*/
|
||||
module dmd.ast_node;
|
||||
|
||||
import dmd.root.rootobject : RootObject;
|
||||
import dmd.visitor : Visitor;
|
||||
|
||||
/// The base class of all AST nodes.
|
||||
extern (C++) abstract class ASTNode : RootObject
|
||||
{
|
||||
/**
|
||||
* Visits this AST node using the given visitor.
|
||||
*
|
||||
* Params:
|
||||
* v = the visitor to use when visiting this node
|
||||
*/
|
||||
abstract void accept(Visitor v);
|
||||
}
|
102
gcc/d/dmd/astcodegen.d
Normal file
102
gcc/d/dmd/astcodegen.d
Normal file
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* Defines AST nodes for the code generation stage.
|
||||
*
|
||||
* Documentation: https://dlang.org/phobos/dmd_astcodegen.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/astcodegen.d
|
||||
*/
|
||||
module dmd.astcodegen;
|
||||
|
||||
|
||||
struct ASTCodegen
|
||||
{
|
||||
public import dmd.aggregate;
|
||||
public import dmd.aliasthis;
|
||||
public import dmd.arraytypes;
|
||||
public import dmd.attrib;
|
||||
public import dmd.cond;
|
||||
public import dmd.dclass;
|
||||
public import dmd.declaration;
|
||||
public import dmd.denum;
|
||||
public import dmd.dimport;
|
||||
public import dmd.dmodule;
|
||||
public import dmd.dstruct;
|
||||
public import dmd.dsymbol;
|
||||
public import dmd.dtemplate;
|
||||
public import dmd.dversion;
|
||||
public import dmd.expression;
|
||||
public import dmd.func;
|
||||
public import dmd.hdrgen;
|
||||
public import dmd.init;
|
||||
public import dmd.initsem;
|
||||
public import dmd.mtype;
|
||||
public import dmd.nspace;
|
||||
public import dmd.statement;
|
||||
public import dmd.staticassert;
|
||||
public import dmd.typesem;
|
||||
public import dmd.ctfeexpr;
|
||||
public import dmd.init : Designator;
|
||||
|
||||
|
||||
alias initializerToExpression = dmd.initsem.initializerToExpression;
|
||||
alias typeToExpression = dmd.typesem.typeToExpression;
|
||||
alias UserAttributeDeclaration = dmd.attrib.UserAttributeDeclaration;
|
||||
alias Ensure = dmd.func.Ensure; // workaround for bug in older DMD frontends
|
||||
alias ErrorExp = dmd.expression.ErrorExp;
|
||||
|
||||
alias MODFlags = dmd.mtype.MODFlags;
|
||||
alias Type = dmd.mtype.Type;
|
||||
alias Parameter = dmd.mtype.Parameter;
|
||||
alias Tarray = dmd.mtype.Tarray;
|
||||
alias Taarray = dmd.mtype.Taarray;
|
||||
alias Tbool = dmd.mtype.Tbool;
|
||||
alias Tchar = dmd.mtype.Tchar;
|
||||
alias Tdchar = dmd.mtype.Tdchar;
|
||||
alias Tdelegate = dmd.mtype.Tdelegate;
|
||||
alias Tenum = dmd.mtype.Tenum;
|
||||
alias Terror = dmd.mtype.Terror;
|
||||
alias Tfloat32 = dmd.mtype.Tfloat32;
|
||||
alias Tfloat64 = dmd.mtype.Tfloat64;
|
||||
alias Tfloat80 = dmd.mtype.Tfloat80;
|
||||
alias Tfunction = dmd.mtype.Tfunction;
|
||||
alias Tpointer = dmd.mtype.Tpointer;
|
||||
alias Treference = dmd.mtype.Treference;
|
||||
alias Tident = dmd.mtype.Tident;
|
||||
alias Tint8 = dmd.mtype.Tint8;
|
||||
alias Tint16 = dmd.mtype.Tint16;
|
||||
alias Tint32 = dmd.mtype.Tint32;
|
||||
alias Tint64 = dmd.mtype.Tint64;
|
||||
alias Tsarray = dmd.mtype.Tsarray;
|
||||
alias Tstruct = dmd.mtype.Tstruct;
|
||||
alias Tuns8 = dmd.mtype.Tuns8;
|
||||
alias Tuns16 = dmd.mtype.Tuns16;
|
||||
alias Tuns32 = dmd.mtype.Tuns32;
|
||||
alias Tuns64 = dmd.mtype.Tuns64;
|
||||
alias Tvoid = dmd.mtype.Tvoid;
|
||||
alias Twchar = dmd.mtype.Twchar;
|
||||
alias Tnoreturn = dmd.mtype.Tnoreturn;
|
||||
|
||||
alias Timaginary32 = dmd.mtype.Timaginary32;
|
||||
alias Timaginary64 = dmd.mtype.Timaginary64;
|
||||
alias Timaginary80 = dmd.mtype.Timaginary80;
|
||||
alias Tcomplex32 = dmd.mtype.Tcomplex32;
|
||||
alias Tcomplex64 = dmd.mtype.Tcomplex64;
|
||||
alias Tcomplex80 = dmd.mtype.Tcomplex80;
|
||||
|
||||
alias ParameterList = dmd.mtype.ParameterList;
|
||||
alias VarArg = dmd.mtype.VarArg;
|
||||
alias STC = dmd.declaration.STC;
|
||||
alias Dsymbol = dmd.dsymbol.Dsymbol;
|
||||
alias Dsymbols = dmd.dsymbol.Dsymbols;
|
||||
alias Visibility = dmd.dsymbol.Visibility;
|
||||
|
||||
alias stcToBuffer = dmd.hdrgen.stcToBuffer;
|
||||
alias linkageToChars = dmd.hdrgen.linkageToChars;
|
||||
alias visibilityToChars = dmd.hdrgen.visibilityToChars;
|
||||
|
||||
alias isType = dmd.dtemplate.isType;
|
||||
alias isExpression = dmd.dtemplate.isExpression;
|
||||
alias isTuple = dmd.dtemplate.isTuple;
|
||||
|
||||
alias IgnoreErrors = dmd.dsymbol.IgnoreErrors;
|
||||
alias PASS = dmd.dsymbol.PASS;
|
||||
}
|
391
gcc/d/dmd/astenums.d
Normal file
391
gcc/d/dmd/astenums.d
Normal file
|
@ -0,0 +1,391 @@
|
|||
/**
|
||||
* Defines enums common to dmd and dmd as parse library.
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/astenums.d, _astenums.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_astenums.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/astenums.d
|
||||
*/
|
||||
|
||||
module dmd.astenums;
|
||||
|
||||
enum Sizeok : ubyte
|
||||
{
|
||||
none, /// size of aggregate is not yet able to compute
|
||||
fwd, /// size of aggregate is ready to compute
|
||||
inProcess, /// in the midst of computing the size
|
||||
done, /// size of aggregate is set correctly
|
||||
}
|
||||
|
||||
enum Baseok : ubyte
|
||||
{
|
||||
none, /// base classes not computed yet
|
||||
start, /// in process of resolving base classes
|
||||
done, /// all base classes are resolved
|
||||
semanticdone, /// all base classes semantic done
|
||||
}
|
||||
|
||||
enum MODFlags : int
|
||||
{
|
||||
const_ = 1, // type is const
|
||||
immutable_ = 4, // type is immutable
|
||||
shared_ = 2, // type is shared
|
||||
wild = 8, // type is wild
|
||||
wildconst = (MODFlags.wild | MODFlags.const_), // type is wild const
|
||||
mutable = 0x10, // type is mutable (only used in wildcard matching)
|
||||
}
|
||||
|
||||
alias MOD = ubyte;
|
||||
|
||||
enum STC : ulong // transfer changes to declaration.h
|
||||
{
|
||||
undefined_ = 0,
|
||||
|
||||
static_ = 1, /// `static`
|
||||
extern_ = 2, /// `extern`
|
||||
const_ = 4, /// `const`
|
||||
final_ = 8, /// `final`
|
||||
|
||||
abstract_ = 0x10, /// `abstract`
|
||||
parameter = 0x20, /// is function parameter
|
||||
field = 0x40, /// is field of struct, union or class
|
||||
override_ = 0x80, /// `override`
|
||||
|
||||
auto_ = 0x100, /// `auto`
|
||||
synchronized_ = 0x200, /// `synchronized`
|
||||
deprecated_ = 0x400, /// `deprecated`
|
||||
in_ = 0x800, /// `in` parameter
|
||||
|
||||
out_ = 0x1000, /// `out` parameter
|
||||
lazy_ = 0x2000, /// `lazy` parameter
|
||||
foreach_ = 0x4000, /// variable for foreach loop
|
||||
variadic = 0x8000, /// the `variadic` parameter in: T foo(T a, U b, V variadic...)
|
||||
|
||||
ctorinit = 0x1_0000, /// can only be set inside constructor
|
||||
templateparameter = 0x2_0000, /// template parameter
|
||||
ref_ = 0x4_0000, /// `ref`
|
||||
scope_ = 0x8_0000, /// `scope`
|
||||
|
||||
maybescope = 0x10_0000, /// parameter might be `scope`
|
||||
scopeinferred = 0x20_0000, /// `scope` has been inferred and should not be part of mangling, `scope_` must also be set
|
||||
return_ = 0x40_0000, /// 'return ref' or 'return scope' for function parameters
|
||||
returnScope = 0x80_0000, /// if `ref return scope` then resolve to `ref` and `return scope`
|
||||
|
||||
returninferred = 0x100_0000, /// `return` has been inferred and should not be part of mangling, `return_` must also be set
|
||||
immutable_ = 0x200_0000, /// `immutable`
|
||||
init = 0x400_0000, /// has explicit initializer
|
||||
manifest = 0x800_0000, /// manifest constant
|
||||
|
||||
nodtor = 0x1000_0000, /// do not run destructor
|
||||
nothrow_ = 0x2000_0000, /// `nothrow` meaning never throws exceptions
|
||||
pure_ = 0x4000_0000, /// `pure` function
|
||||
tls = 0x8000_0000, /// thread local
|
||||
|
||||
alias_ = 0x1_0000_0000, /// `alias` parameter
|
||||
shared_ = 0x2_0000_0000, /// accessible from multiple threads
|
||||
gshared = 0x4_0000_0000, /// accessible from multiple threads, but not typed as `shared`
|
||||
wild = 0x8_0000_0000, /// for wild type constructor
|
||||
|
||||
property = 0x10_0000_0000, /// `@property`
|
||||
safe = 0x20_0000_0000, /// `@safe`
|
||||
trusted = 0x40_0000_0000, /// `@trusted`
|
||||
system = 0x80_0000_0000, /// `@system`
|
||||
|
||||
ctfe = 0x100_0000_0000, /// can be used in CTFE, even if it is static
|
||||
disable = 0x200_0000_0000, /// for functions that are not callable
|
||||
result = 0x400_0000_0000, /// for result variables passed to out contracts
|
||||
nodefaultctor = 0x800_0000_0000, /// must be set inside constructor
|
||||
|
||||
temp = 0x1000_0000_0000, /// temporary variable
|
||||
rvalue = 0x2000_0000_0000, /// force rvalue for variables
|
||||
nogc = 0x4000_0000_0000, /// `@nogc`
|
||||
autoref = 0x8000_0000_0000, /// Mark for the already deduced `auto ref` parameter
|
||||
|
||||
inference = 0x1_0000_0000_0000, /// do attribute inference
|
||||
exptemp = 0x2_0000_0000_0000, /// temporary variable that has lifetime restricted to an expression
|
||||
future = 0x4_0000_0000_0000, /// introducing new base class function
|
||||
local = 0x8_0000_0000_0000, /// do not forward (see dmd.dsymbol.ForwardingScopeDsymbol).
|
||||
|
||||
live = 0x10_0000_0000_0000, /// function `@live` attribute
|
||||
register = 0x20_0000_0000_0000, /// `register` storage class (ImportC)
|
||||
volatile_ = 0x40_0000_0000_0000, /// destined for volatile in the back end
|
||||
|
||||
safeGroup = STC.safe | STC.trusted | STC.system,
|
||||
IOR = STC.in_ | STC.ref_ | STC.out_,
|
||||
TYPECTOR = (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild),
|
||||
FUNCATTR = (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.property | STC.live |
|
||||
safeGroup),
|
||||
|
||||
/* These are visible to the user, i.e. are expressed by the user
|
||||
*/
|
||||
visibleStorageClasses =
|
||||
(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.const_ | STC.final_ | STC.abstract_ | STC.synchronized_ |
|
||||
STC.deprecated_ | STC.future | STC.override_ | STC.lazy_ | STC.alias_ | STC.out_ | STC.in_ | STC.manifest |
|
||||
STC.immutable_ | STC.shared_ | STC.wild | STC.nothrow_ | STC.nogc | STC.pure_ | STC.ref_ | STC.return_ | STC.tls | STC.gshared |
|
||||
STC.property | STC.safeGroup | STC.disable | STC.local | STC.live),
|
||||
|
||||
/* These storage classes "flow through" to the inner scope of a Dsymbol
|
||||
*/
|
||||
flowThruAggregate = STC.safeGroup, /// for an AggregateDeclaration
|
||||
flowThruFunction = ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.abstract_ | STC.deprecated_ | STC.override_ |
|
||||
STC.TYPECTOR | STC.final_ | STC.tls | STC.gshared | STC.ref_ | STC.return_ | STC.property |
|
||||
STC.nothrow_ | STC.pure_ | STC.safe | STC.trusted | STC.system), /// for a FuncDeclaration
|
||||
|
||||
}
|
||||
|
||||
/********
|
||||
* Determine if it's the ambigous case of where `return` attaches to.
|
||||
* Params:
|
||||
* stc = STC flags
|
||||
* Returns:
|
||||
* true if (`ref` | `out`) and `scope` and `return`
|
||||
*/
|
||||
@safe pure @nogc nothrow
|
||||
bool isRefReturnScope(const ulong stc)
|
||||
{
|
||||
return (stc & (STC.scope_ | STC.return_)) == (STC.scope_ | STC.return_) &&
|
||||
stc & (STC.ref_ | STC.out_);
|
||||
}
|
||||
|
||||
/* This is different from the one in declaration.d, make that fix a separate PR */
|
||||
static if (0)
|
||||
extern (C++) __gshared const(StorageClass) STCStorageClass =
|
||||
(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.const_ | STC.final_ |
|
||||
STC.abstract_ | STC.synchronized_ | STC.deprecated_ | STC.override_ | STC.lazy_ |
|
||||
STC.alias_ | STC.out_ | STC.in_ | STC.manifest | STC.immutable_ | STC.shared_ |
|
||||
STC.wild | STC.nothrow_ | STC.nogc | STC.pure_ | STC.ref_ | STC.return_ | STC.tls |
|
||||
STC.gshared | STC.property | STC.live |
|
||||
STC.safeGroup | STC.disable);
|
||||
|
||||
enum TY : ubyte
|
||||
{
|
||||
Tarray, // slice array, aka T[]
|
||||
Tsarray, // static array, aka T[dimension]
|
||||
Taarray, // associative array, aka T[type]
|
||||
Tpointer,
|
||||
Treference,
|
||||
Tfunction,
|
||||
Tident,
|
||||
Tclass,
|
||||
Tstruct,
|
||||
Tenum,
|
||||
|
||||
Tdelegate,
|
||||
Tnone,
|
||||
Tvoid,
|
||||
Tint8,
|
||||
Tuns8,
|
||||
Tint16,
|
||||
Tuns16,
|
||||
Tint32,
|
||||
Tuns32,
|
||||
Tint64,
|
||||
|
||||
Tuns64,
|
||||
Tfloat32,
|
||||
Tfloat64,
|
||||
Tfloat80,
|
||||
Timaginary32,
|
||||
Timaginary64,
|
||||
Timaginary80,
|
||||
Tcomplex32,
|
||||
Tcomplex64,
|
||||
Tcomplex80,
|
||||
|
||||
Tbool,
|
||||
Tchar,
|
||||
Twchar,
|
||||
Tdchar,
|
||||
Terror,
|
||||
Tinstance,
|
||||
Ttypeof,
|
||||
Ttuple,
|
||||
Tslice,
|
||||
Treturn,
|
||||
|
||||
Tnull,
|
||||
Tvector,
|
||||
Tint128,
|
||||
Tuns128,
|
||||
Ttraits,
|
||||
Tmixin,
|
||||
Tnoreturn,
|
||||
Ttag,
|
||||
TMAX
|
||||
}
|
||||
|
||||
alias Tarray = TY.Tarray;
|
||||
alias Tsarray = TY.Tsarray;
|
||||
alias Taarray = TY.Taarray;
|
||||
alias Tpointer = TY.Tpointer;
|
||||
alias Treference = TY.Treference;
|
||||
alias Tfunction = TY.Tfunction;
|
||||
alias Tident = TY.Tident;
|
||||
alias Tclass = TY.Tclass;
|
||||
alias Tstruct = TY.Tstruct;
|
||||
alias Tenum = TY.Tenum;
|
||||
alias Tdelegate = TY.Tdelegate;
|
||||
alias Tnone = TY.Tnone;
|
||||
alias Tvoid = TY.Tvoid;
|
||||
alias Tint8 = TY.Tint8;
|
||||
alias Tuns8 = TY.Tuns8;
|
||||
alias Tint16 = TY.Tint16;
|
||||
alias Tuns16 = TY.Tuns16;
|
||||
alias Tint32 = TY.Tint32;
|
||||
alias Tuns32 = TY.Tuns32;
|
||||
alias Tint64 = TY.Tint64;
|
||||
alias Tuns64 = TY.Tuns64;
|
||||
alias Tfloat32 = TY.Tfloat32;
|
||||
alias Tfloat64 = TY.Tfloat64;
|
||||
alias Tfloat80 = TY.Tfloat80;
|
||||
alias Timaginary32 = TY.Timaginary32;
|
||||
alias Timaginary64 = TY.Timaginary64;
|
||||
alias Timaginary80 = TY.Timaginary80;
|
||||
alias Tcomplex32 = TY.Tcomplex32;
|
||||
alias Tcomplex64 = TY.Tcomplex64;
|
||||
alias Tcomplex80 = TY.Tcomplex80;
|
||||
alias Tbool = TY.Tbool;
|
||||
alias Tchar = TY.Tchar;
|
||||
alias Twchar = TY.Twchar;
|
||||
alias Tdchar = TY.Tdchar;
|
||||
alias Terror = TY.Terror;
|
||||
alias Tinstance = TY.Tinstance;
|
||||
alias Ttypeof = TY.Ttypeof;
|
||||
alias Ttuple = TY.Ttuple;
|
||||
alias Tslice = TY.Tslice;
|
||||
alias Treturn = TY.Treturn;
|
||||
alias Tnull = TY.Tnull;
|
||||
alias Tvector = TY.Tvector;
|
||||
alias Tint128 = TY.Tint128;
|
||||
alias Tuns128 = TY.Tuns128;
|
||||
alias Ttraits = TY.Ttraits;
|
||||
alias Tmixin = TY.Tmixin;
|
||||
alias Tnoreturn = TY.Tnoreturn;
|
||||
alias Ttag = TY.Ttag;
|
||||
alias TMAX = TY.TMAX;
|
||||
|
||||
enum TFlags
|
||||
{
|
||||
integral = 1,
|
||||
floating = 2,
|
||||
unsigned = 4,
|
||||
real_ = 8,
|
||||
imaginary = 0x10,
|
||||
complex = 0x20,
|
||||
}
|
||||
|
||||
enum PKG : int
|
||||
{
|
||||
unknown, /// not yet determined whether it's a package.d or not
|
||||
module_, /// already determined that's an actual package.d
|
||||
package_, /// already determined that's an actual package
|
||||
}
|
||||
|
||||
enum ThreeState : ubyte
|
||||
{
|
||||
none, /// state is not yet computed
|
||||
no, /// state is false
|
||||
yes, /// state is true
|
||||
}
|
||||
|
||||
enum TRUST : ubyte
|
||||
{
|
||||
default_ = 0,
|
||||
system = 1, // @system (same as TRUST.default)
|
||||
trusted = 2, // @trusted
|
||||
safe = 3, // @safe
|
||||
}
|
||||
|
||||
enum PURE : ubyte
|
||||
{
|
||||
impure = 0, // not pure at all
|
||||
fwdref = 1, // it's pure, but not known which level yet
|
||||
weak = 2, // no mutable globals are read or written
|
||||
const_ = 3, // parameters are values or const
|
||||
strong = 4, // parameters are values or immutable
|
||||
}
|
||||
|
||||
// Whether alias this dependency is recursive or not
|
||||
enum AliasThisRec : int
|
||||
{
|
||||
no = 0, // no alias this recursion
|
||||
yes = 1, // alias this has recursive dependency
|
||||
fwdref = 2, // not yet known
|
||||
typeMask = 3, // mask to read no/yes/fwdref
|
||||
tracing = 0x4, // mark in progress of implicitConvTo/deduceWild
|
||||
tracingDT = 0x8, // mark in progress of deduceType
|
||||
}
|
||||
|
||||
/***************
|
||||
* Variadic argument lists
|
||||
* https://dlang.org/spec/function.html#variadic
|
||||
*/
|
||||
enum VarArg : ubyte
|
||||
{
|
||||
none = 0, /// fixed number of arguments
|
||||
variadic = 1, /// (T t, ...) can be C-style (core.stdc.stdarg) or D-style (core.vararg)
|
||||
typesafe = 2, /// (T t ...) typesafe https://dlang.org/spec/function.html#typesafe_variadic_functions
|
||||
/// or https://dlang.org/spec/function.html#typesafe_variadic_functions
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Identify Statement types with this enum rather than
|
||||
* virtual functions
|
||||
*/
|
||||
enum STMT : ubyte
|
||||
{
|
||||
Error,
|
||||
Peel,
|
||||
Exp, DtorExp,
|
||||
Compile,
|
||||
Compound, CompoundDeclaration, CompoundAsm,
|
||||
UnrolledLoop,
|
||||
Scope,
|
||||
Forwarding,
|
||||
While,
|
||||
Do,
|
||||
For,
|
||||
Foreach,
|
||||
ForeachRange,
|
||||
If,
|
||||
Conditional,
|
||||
StaticForeach,
|
||||
Pragma,
|
||||
StaticAssert,
|
||||
Switch,
|
||||
Case,
|
||||
CaseRange,
|
||||
Default,
|
||||
GotoDefault,
|
||||
GotoCase,
|
||||
SwitchError,
|
||||
Return,
|
||||
Break,
|
||||
Continue,
|
||||
Synchronized,
|
||||
With,
|
||||
TryCatch,
|
||||
TryFinally,
|
||||
ScopeGuard,
|
||||
Throw,
|
||||
Debug,
|
||||
Goto,
|
||||
Label,
|
||||
Asm, InlineAsm, GccAsm,
|
||||
Import,
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Discriminant for which kind of initializer
|
||||
*/
|
||||
enum InitKind : ubyte
|
||||
{
|
||||
void_,
|
||||
error,
|
||||
struct_,
|
||||
array,
|
||||
exp,
|
||||
C_,
|
||||
}
|
||||
|
1320
gcc/d/dmd/attrib.c
1320
gcc/d/dmd/attrib.c
File diff suppressed because it is too large
Load diff
1518
gcc/d/dmd/attrib.d
Normal file
1518
gcc/d/dmd/attrib.d
Normal file
File diff suppressed because it is too large
Load diff
|
@ -10,13 +10,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "root/port.h"
|
||||
#include "dsymbol.h"
|
||||
|
||||
class Expression;
|
||||
class Statement;
|
||||
class LabelDsymbol;
|
||||
class Initializer;
|
||||
class Module;
|
||||
class Condition;
|
||||
class StaticForeach;
|
||||
|
||||
|
@ -27,12 +24,7 @@ class AttribDeclaration : public Dsymbol
|
|||
public:
|
||||
Dsymbols *decl; // array of Dsymbol's
|
||||
|
||||
AttribDeclaration(Dsymbols *decl);
|
||||
virtual Dsymbols *include(Scope *sc);
|
||||
int apply(Dsymbol_apply_ft_t fp, void *param);
|
||||
static Scope *createNewScope(Scope *sc,
|
||||
StorageClass newstc, LINK linkage, CPPMANGLE cppmangle, Prot protection,
|
||||
int explicitProtection, AlignDeclaration *aligndecl, PINLINE inlining);
|
||||
virtual Scope *newScope(Scope *sc);
|
||||
void addMember(Scope *sc, ScopeDsymbol *sds);
|
||||
void setScope(Scope *sc);
|
||||
|
@ -40,7 +32,7 @@ public:
|
|||
void addComment(const utf8_t *comment);
|
||||
const char *kind() const;
|
||||
bool oneMember(Dsymbol **ps, Identifier *ident);
|
||||
void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
|
||||
void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
|
||||
bool hasPointers();
|
||||
bool hasStaticCtorOrDtor();
|
||||
void checkCtorConstInit();
|
||||
|
@ -55,8 +47,7 @@ class StorageClassDeclaration : public AttribDeclaration
|
|||
public:
|
||||
StorageClass stc;
|
||||
|
||||
StorageClassDeclaration(StorageClass stc, Dsymbols *decl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
StorageClassDeclaration *syntaxCopy(Dsymbol *s);
|
||||
Scope *newScope(Scope *sc);
|
||||
bool oneMember(Dsymbol **ps, Identifier *ident);
|
||||
void addMember(Scope *sc, ScopeDsymbol *sds);
|
||||
|
@ -71,11 +62,9 @@ public:
|
|||
Expression *msg;
|
||||
const char *msgstr;
|
||||
|
||||
DeprecatedDeclaration(Expression *msg, Dsymbols *decl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
DeprecatedDeclaration *syntaxCopy(Dsymbol *s);
|
||||
Scope *newScope(Scope *sc);
|
||||
void setScope(Scope *sc);
|
||||
const char *getMessage();
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
|
@ -84,11 +73,10 @@ class LinkDeclaration : public AttribDeclaration
|
|||
public:
|
||||
LINK linkage;
|
||||
|
||||
LinkDeclaration(LINK p, Dsymbols *decl);
|
||||
static LinkDeclaration *create(LINK p, Dsymbols *decl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
static LinkDeclaration *create(const Loc &loc, LINK p, Dsymbols *decl);
|
||||
LinkDeclaration *syntaxCopy(Dsymbol *s);
|
||||
Scope *newScope(Scope *sc);
|
||||
const char *toChars();
|
||||
const char *toChars() const;
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
|
@ -97,40 +85,48 @@ class CPPMangleDeclaration : public AttribDeclaration
|
|||
public:
|
||||
CPPMANGLE cppmangle;
|
||||
|
||||
CPPMangleDeclaration(CPPMANGLE p, Dsymbols *decl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
CPPMangleDeclaration *syntaxCopy(Dsymbol *s);
|
||||
Scope *newScope(Scope *sc);
|
||||
const char *toChars();
|
||||
void setScope(Scope *sc);
|
||||
const char *toChars() const;
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
class ProtDeclaration : public AttribDeclaration
|
||||
class CPPNamespaceDeclaration : public AttribDeclaration
|
||||
{
|
||||
public:
|
||||
Prot protection;
|
||||
Identifiers* pkg_identifiers;
|
||||
Expression *exp;
|
||||
|
||||
ProtDeclaration(Loc loc, Prot p, Dsymbols *decl);
|
||||
ProtDeclaration(Loc loc, Identifiers* pkg_identifiers, Dsymbols *decl);
|
||||
CPPNamespaceDeclaration *syntaxCopy(Dsymbol *s);
|
||||
Scope *newScope(Scope *sc);
|
||||
const char *toChars() const;
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
class VisibilityDeclaration : public AttribDeclaration
|
||||
{
|
||||
public:
|
||||
Visibility visibility;
|
||||
DArray<Identifier*> pkg_identifiers;
|
||||
|
||||
VisibilityDeclaration *syntaxCopy(Dsymbol *s);
|
||||
Scope *newScope(Scope *sc);
|
||||
void addMember(Scope *sc, ScopeDsymbol *sds);
|
||||
const char *kind() const;
|
||||
const char *toPrettyChars(bool unused);
|
||||
VisibilityDeclaration *isVisibilityDeclaration() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
class AlignDeclaration : public AttribDeclaration
|
||||
{
|
||||
public:
|
||||
Expression *ealign;
|
||||
Expressions *alignExps;
|
||||
structalign_t salign;
|
||||
|
||||
AlignDeclaration(Loc loc, Expression *ealign, Dsymbols *decl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
AlignDeclaration(const Loc &loc, Expression *ealign, Dsymbols *decl);
|
||||
AlignDeclaration *syntaxCopy(Dsymbol *s);
|
||||
Scope *newScope(Scope *sc);
|
||||
structalign_t getAlignment(Scope *sc);
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
|
@ -143,10 +139,9 @@ public:
|
|||
unsigned anonstructsize; // size of anonymous struct
|
||||
unsigned anonalignsize; // size of anonymous struct for alignment purposes
|
||||
|
||||
AnonDeclaration(Loc loc, bool isunion, Dsymbols *decl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
AnonDeclaration *syntaxCopy(Dsymbol *s);
|
||||
void setScope(Scope *sc);
|
||||
void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
|
||||
void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
|
||||
const char *kind() const;
|
||||
AnonDeclaration *isAnonDeclaration() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -157,9 +152,9 @@ class PragmaDeclaration : public AttribDeclaration
|
|||
public:
|
||||
Expressions *args; // array of Expression's
|
||||
|
||||
PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
PragmaDeclaration *syntaxCopy(Dsymbol *s);
|
||||
Scope *newScope(Scope *sc);
|
||||
PINLINE evalPragmaInline(Scope* sc);
|
||||
const char *kind() const;
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
@ -170,8 +165,7 @@ public:
|
|||
Condition *condition;
|
||||
Dsymbols *elsedecl; // array of Dsymbol's for else block
|
||||
|
||||
ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
ConditionalDeclaration *syntaxCopy(Dsymbol *s);
|
||||
bool oneMember(Dsymbol **ps, Identifier *ident);
|
||||
Dsymbols *include(Scope *sc);
|
||||
void addComment(const utf8_t *comment);
|
||||
|
@ -186,8 +180,7 @@ public:
|
|||
bool addisdone;
|
||||
bool onStack;
|
||||
|
||||
StaticIfDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
StaticIfDeclaration *syntaxCopy(Dsymbol *s);
|
||||
Dsymbols *include(Scope *sc);
|
||||
void addMember(Scope *sc, ScopeDsymbol *sds);
|
||||
void setScope(Scope *sc);
|
||||
|
@ -205,8 +198,7 @@ public:
|
|||
bool cached;
|
||||
Dsymbols *cache;
|
||||
|
||||
StaticForeachDeclaration(StaticForeach *sfe, Dsymbols *decl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
StaticForeachDeclaration *syntaxCopy(Dsymbol *s);
|
||||
bool oneMember(Dsymbol **ps, Identifier *ident);
|
||||
Dsymbols *include(Scope *sc);
|
||||
void addMember(Scope *sc, ScopeDsymbol *sds);
|
||||
|
@ -222,7 +214,6 @@ class ForwardingAttribDeclaration : public AttribDeclaration
|
|||
public:
|
||||
ForwardingScopeDsymbol *sym;
|
||||
|
||||
ForwardingAttribDeclaration(Dsymbols *decl);
|
||||
Scope *newScope(Scope *sc);
|
||||
void addMember(Scope *sc, ScopeDsymbol *sds);
|
||||
ForwardingAttribDeclaration *isForwardingAttribDeclaration() { return this; }
|
||||
|
@ -239,8 +230,7 @@ public:
|
|||
ScopeDsymbol *scopesym;
|
||||
bool compiled;
|
||||
|
||||
CompileDeclaration(Loc loc, Expressions *exps);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
CompileDeclaration *syntaxCopy(Dsymbol *s);
|
||||
void addMember(Scope *sc, ScopeDsymbol *sds);
|
||||
void setScope(Scope *sc);
|
||||
const char *kind() const;
|
||||
|
@ -256,11 +246,9 @@ class UserAttributeDeclaration : public AttribDeclaration
|
|||
public:
|
||||
Expressions *atts;
|
||||
|
||||
UserAttributeDeclaration(Expressions *atts, Dsymbols *decl);
|
||||
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||
UserAttributeDeclaration *syntaxCopy(Dsymbol *s);
|
||||
Scope *newScope(Scope *sc);
|
||||
void setScope(Scope *sc);
|
||||
static Expressions *concat(Expressions *udas1, Expressions *udas2);
|
||||
Expressions *getAttributes();
|
||||
const char *kind() const;
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
|
|
@ -1,506 +0,0 @@
|
|||
|
||||
/* Compiler implementation of the D programming language
|
||||
* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
*/
|
||||
|
||||
#include "statement.h"
|
||||
#include "declaration.h"
|
||||
#include "aggregate.h"
|
||||
#include "id.h"
|
||||
|
||||
/* Only valid after semantic analysis
|
||||
* If 'mustNotThrow' is true, generate an error if it throws
|
||||
*/
|
||||
int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow)
|
||||
{
|
||||
class BlockExit : public Visitor
|
||||
{
|
||||
public:
|
||||
FuncDeclaration *func;
|
||||
bool mustNotThrow;
|
||||
int result;
|
||||
|
||||
BlockExit(FuncDeclaration *func, bool mustNotThrow)
|
||||
: func(func), mustNotThrow(mustNotThrow)
|
||||
{
|
||||
result = BEnone;
|
||||
}
|
||||
|
||||
void visit(Statement *s)
|
||||
{
|
||||
printf("Statement::blockExit(%p)\n", s);
|
||||
printf("%s\n", s->toChars());
|
||||
assert(0);
|
||||
result = BEany;
|
||||
}
|
||||
|
||||
void visit(ErrorStatement *)
|
||||
{
|
||||
result = BEany;
|
||||
}
|
||||
|
||||
void visit(ExpStatement *s)
|
||||
{
|
||||
result = BEfallthru;
|
||||
if (s->exp)
|
||||
{
|
||||
if (s->exp->op == TOKhalt)
|
||||
{
|
||||
result = BEhalt;
|
||||
return;
|
||||
}
|
||||
if (s->exp->op == TOKassert)
|
||||
{
|
||||
AssertExp *a = (AssertExp *)s->exp;
|
||||
if (a->e1->isBool(false)) // if it's an assert(0)
|
||||
{
|
||||
result = BEhalt;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (s->exp->type->toBasetype()->isTypeNoreturn())
|
||||
result = BEhalt;
|
||||
if (canThrow(s->exp, func, mustNotThrow))
|
||||
result |= BEthrow;
|
||||
}
|
||||
}
|
||||
|
||||
void visit(CompileStatement *)
|
||||
{
|
||||
assert(global.errors);
|
||||
result = BEfallthru;
|
||||
}
|
||||
|
||||
void visit(CompoundStatement *cs)
|
||||
{
|
||||
//printf("CompoundStatement::blockExit(%p) %d result = x%X\n", cs, cs->statements->length, result);
|
||||
result = BEfallthru;
|
||||
Statement *slast = NULL;
|
||||
for (size_t i = 0; i < cs->statements->length; i++)
|
||||
{
|
||||
Statement *s = (*cs->statements)[i];
|
||||
if (s)
|
||||
{
|
||||
//printf("result = x%x\n", result);
|
||||
//printf("s: %s\n", s->toChars());
|
||||
if (result & BEfallthru && slast)
|
||||
{
|
||||
slast = slast->last();
|
||||
if (slast && (slast->isCaseStatement() || slast->isDefaultStatement()) &&
|
||||
(s->isCaseStatement() || s->isDefaultStatement()))
|
||||
{
|
||||
// Allow if last case/default was empty
|
||||
CaseStatement *sc = slast->isCaseStatement();
|
||||
DefaultStatement *sd = slast->isDefaultStatement();
|
||||
if (sc && (!sc->statement->hasCode() || sc->statement->isCaseStatement() || sc->statement->isErrorStatement()))
|
||||
;
|
||||
else if (sd && (!sd->statement->hasCode() || sd->statement->isCaseStatement() || sd->statement->isErrorStatement()))
|
||||
;
|
||||
else
|
||||
{
|
||||
const char *gototype = s->isCaseStatement() ? "case" : "default";
|
||||
s->deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(result & BEfallthru) && !s->comeFrom())
|
||||
{
|
||||
if (blockExit(s, func, mustNotThrow) != BEhalt && s->hasCode())
|
||||
s->warning("statement is not reachable");
|
||||
}
|
||||
else
|
||||
{
|
||||
result &= ~BEfallthru;
|
||||
result |= blockExit(s, func, mustNotThrow);
|
||||
}
|
||||
slast = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void visit(UnrolledLoopStatement *uls)
|
||||
{
|
||||
result = BEfallthru;
|
||||
for (size_t i = 0; i < uls->statements->length; i++)
|
||||
{
|
||||
Statement *s = (*uls->statements)[i];
|
||||
if (s)
|
||||
{
|
||||
int r = blockExit(s, func, mustNotThrow);
|
||||
result |= r & ~(BEbreak | BEcontinue | BEfallthru);
|
||||
if ((r & (BEfallthru | BEcontinue | BEbreak)) == 0)
|
||||
result &= ~BEfallthru;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void visit(ScopeStatement *s)
|
||||
{
|
||||
//printf("ScopeStatement::blockExit(%p)\n", s->statement);
|
||||
result = s->statement ? blockExit(s->statement, func, mustNotThrow) : BEfallthru;
|
||||
}
|
||||
|
||||
void visit(WhileStatement *)
|
||||
{
|
||||
assert(global.errors);
|
||||
result = BEfallthru;
|
||||
}
|
||||
|
||||
void visit(DoStatement *s)
|
||||
{
|
||||
if (s->_body)
|
||||
{
|
||||
result = blockExit(s->_body, func, mustNotThrow);
|
||||
if (result == BEbreak)
|
||||
{
|
||||
result = BEfallthru;
|
||||
return;
|
||||
}
|
||||
if (result & BEcontinue)
|
||||
result |= BEfallthru;
|
||||
}
|
||||
else
|
||||
result = BEfallthru;
|
||||
if (result & BEfallthru)
|
||||
{
|
||||
if (canThrow(s->condition, func, mustNotThrow))
|
||||
result |= BEthrow;
|
||||
if (!(result & BEbreak) && s->condition->isBool(true))
|
||||
result &= ~BEfallthru;
|
||||
}
|
||||
result &= ~(BEbreak | BEcontinue);
|
||||
}
|
||||
|
||||
void visit(ForStatement *s)
|
||||
{
|
||||
result = BEfallthru;
|
||||
if (s->_init)
|
||||
{
|
||||
result = blockExit(s->_init, func, mustNotThrow);
|
||||
if (!(result & BEfallthru))
|
||||
return;
|
||||
}
|
||||
if (s->condition)
|
||||
{
|
||||
if (canThrow(s->condition, func, mustNotThrow))
|
||||
result |= BEthrow;
|
||||
if (s->condition->isBool(true))
|
||||
result &= ~BEfallthru;
|
||||
else if (s->condition->isBool(false))
|
||||
return;
|
||||
}
|
||||
else
|
||||
result &= ~BEfallthru; // the body must do the exiting
|
||||
if (s->_body)
|
||||
{
|
||||
int r = blockExit(s->_body, func, mustNotThrow);
|
||||
if (r & (BEbreak | BEgoto))
|
||||
result |= BEfallthru;
|
||||
result |= r & ~(BEfallthru | BEbreak | BEcontinue);
|
||||
}
|
||||
if (s->increment && canThrow(s->increment, func, mustNotThrow))
|
||||
result |= BEthrow;
|
||||
}
|
||||
|
||||
void visit(ForeachStatement *s)
|
||||
{
|
||||
result = BEfallthru;
|
||||
if (canThrow(s->aggr, func, mustNotThrow))
|
||||
result |= BEthrow;
|
||||
if (s->_body)
|
||||
result |= blockExit(s->_body, func, mustNotThrow) & ~(BEbreak | BEcontinue);
|
||||
}
|
||||
|
||||
void visit(ForeachRangeStatement *)
|
||||
{
|
||||
assert(global.errors);
|
||||
result = BEfallthru;
|
||||
}
|
||||
|
||||
void visit(IfStatement *s)
|
||||
{
|
||||
//printf("IfStatement::blockExit(%p)\n", s);
|
||||
|
||||
result = BEnone;
|
||||
if (canThrow(s->condition, func, mustNotThrow))
|
||||
result |= BEthrow;
|
||||
if (s->condition->isBool(true))
|
||||
{
|
||||
if (s->ifbody)
|
||||
result |= blockExit(s->ifbody, func, mustNotThrow);
|
||||
else
|
||||
result |= BEfallthru;
|
||||
}
|
||||
else if (s->condition->isBool(false))
|
||||
{
|
||||
if (s->elsebody)
|
||||
result |= blockExit(s->elsebody, func, mustNotThrow);
|
||||
else
|
||||
result |= BEfallthru;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s->ifbody)
|
||||
result |= blockExit(s->ifbody, func, mustNotThrow);
|
||||
else
|
||||
result |= BEfallthru;
|
||||
if (s->elsebody)
|
||||
result |= blockExit(s->elsebody, func, mustNotThrow);
|
||||
else
|
||||
result |= BEfallthru;
|
||||
}
|
||||
//printf("IfStatement::blockExit(%p) = x%x\n", s, result);
|
||||
}
|
||||
|
||||
void visit(ConditionalStatement *s)
|
||||
{
|
||||
result = blockExit(s->ifbody, func, mustNotThrow);
|
||||
if (s->elsebody)
|
||||
result |= blockExit(s->elsebody, func, mustNotThrow);
|
||||
}
|
||||
|
||||
void visit(PragmaStatement *)
|
||||
{
|
||||
result = BEfallthru;
|
||||
}
|
||||
|
||||
void visit(StaticAssertStatement *)
|
||||
{
|
||||
result = BEfallthru;
|
||||
}
|
||||
|
||||
void visit(SwitchStatement *s)
|
||||
{
|
||||
result = BEnone;
|
||||
if (canThrow(s->condition, func, mustNotThrow))
|
||||
result |= BEthrow;
|
||||
if (s->_body)
|
||||
{
|
||||
result |= blockExit(s->_body, func, mustNotThrow);
|
||||
if (result & BEbreak)
|
||||
{
|
||||
result |= BEfallthru;
|
||||
result &= ~BEbreak;
|
||||
}
|
||||
}
|
||||
else
|
||||
result |= BEfallthru;
|
||||
}
|
||||
|
||||
void visit(CaseStatement *s)
|
||||
{
|
||||
result = blockExit(s->statement, func, mustNotThrow);
|
||||
}
|
||||
|
||||
void visit(DefaultStatement *s)
|
||||
{
|
||||
result = blockExit(s->statement, func, mustNotThrow);
|
||||
}
|
||||
|
||||
void visit(GotoDefaultStatement *)
|
||||
{
|
||||
result = BEgoto;
|
||||
}
|
||||
|
||||
void visit(GotoCaseStatement *)
|
||||
{
|
||||
result = BEgoto;
|
||||
}
|
||||
|
||||
void visit(SwitchErrorStatement *)
|
||||
{
|
||||
// Switch errors are non-recoverable
|
||||
result = BEhalt;
|
||||
}
|
||||
|
||||
void visit(ReturnStatement *s)
|
||||
{
|
||||
result = BEreturn;
|
||||
if (s->exp && canThrow(s->exp, func, mustNotThrow))
|
||||
result |= BEthrow;
|
||||
}
|
||||
|
||||
void visit(BreakStatement *s)
|
||||
{
|
||||
//printf("BreakStatement::blockExit(%p) = x%x\n", s, s->ident ? BEgoto : BEbreak);
|
||||
result = s->ident ? BEgoto : BEbreak;
|
||||
}
|
||||
|
||||
void visit(ContinueStatement *s)
|
||||
{
|
||||
result = s->ident ? BEgoto : BEcontinue;
|
||||
}
|
||||
|
||||
void visit(SynchronizedStatement *s)
|
||||
{
|
||||
result = s->_body ? blockExit(s->_body, func, mustNotThrow) : BEfallthru;
|
||||
}
|
||||
|
||||
void visit(WithStatement *s)
|
||||
{
|
||||
result = BEnone;
|
||||
if (canThrow(s->exp, func, mustNotThrow))
|
||||
result = BEthrow;
|
||||
if (s->_body)
|
||||
result |= blockExit(s->_body, func, mustNotThrow);
|
||||
else
|
||||
result |= BEfallthru;
|
||||
}
|
||||
|
||||
void visit(TryCatchStatement *s)
|
||||
{
|
||||
assert(s->_body);
|
||||
result = blockExit(s->_body, func, false);
|
||||
|
||||
int catchresult = 0;
|
||||
for (size_t i = 0; i < s->catches->length; i++)
|
||||
{
|
||||
Catch *c = (*s->catches)[i];
|
||||
if (c->type == Type::terror)
|
||||
continue;
|
||||
|
||||
int cresult;
|
||||
if (c->handler)
|
||||
cresult = blockExit(c->handler, func, mustNotThrow);
|
||||
else
|
||||
cresult = BEfallthru;
|
||||
|
||||
/* If we're catching Object, then there is no throwing
|
||||
*/
|
||||
Identifier *id = c->type->toBasetype()->isClassHandle()->ident;
|
||||
if (c->internalCatch && (cresult & BEfallthru))
|
||||
{
|
||||
// Bugzilla 11542: leave blockExit flags of the body
|
||||
cresult &= ~BEfallthru;
|
||||
}
|
||||
else if (id == Id::Object || id == Id::Throwable)
|
||||
{
|
||||
result &= ~(BEthrow | BEerrthrow);
|
||||
}
|
||||
else if (id == Id::Exception)
|
||||
{
|
||||
result &= ~BEthrow;
|
||||
}
|
||||
catchresult |= cresult;
|
||||
}
|
||||
if (mustNotThrow && (result & BEthrow))
|
||||
{
|
||||
// now explain why this is nothrow
|
||||
blockExit(s->_body, func, mustNotThrow);
|
||||
}
|
||||
result |= catchresult;
|
||||
}
|
||||
|
||||
void visit(TryFinallyStatement *s)
|
||||
{
|
||||
result = BEfallthru;
|
||||
if (s->_body)
|
||||
result = blockExit(s->_body, func, false);
|
||||
|
||||
// check finally body as well, it may throw (bug #4082)
|
||||
int finalresult = BEfallthru;
|
||||
if (s->finalbody)
|
||||
finalresult = blockExit(s->finalbody, func, false);
|
||||
|
||||
// If either body or finalbody halts
|
||||
if (result == BEhalt)
|
||||
finalresult = BEnone;
|
||||
if (finalresult == BEhalt)
|
||||
result = BEnone;
|
||||
|
||||
if (mustNotThrow)
|
||||
{
|
||||
// now explain why this is nothrow
|
||||
if (s->_body && (result & BEthrow))
|
||||
blockExit(s->_body, func, mustNotThrow);
|
||||
if (s->finalbody && (finalresult & BEthrow))
|
||||
blockExit(s->finalbody, func, mustNotThrow);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Bugzilla 13201: Mask to prevent spurious warnings for
|
||||
// destructor call, exit of synchronized statement, etc.
|
||||
if (result == BEhalt && finalresult != BEhalt && s->finalbody &&
|
||||
s->finalbody->hasCode())
|
||||
{
|
||||
s->finalbody->warning("statement is not reachable");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(finalresult & BEfallthru))
|
||||
result &= ~BEfallthru;
|
||||
result |= finalresult & ~BEfallthru;
|
||||
}
|
||||
|
||||
void visit(ScopeGuardStatement *)
|
||||
{
|
||||
// At this point, this statement is just an empty placeholder
|
||||
result = BEfallthru;
|
||||
}
|
||||
|
||||
void visit(ThrowStatement *s)
|
||||
{
|
||||
if (s->internalThrow)
|
||||
{
|
||||
// Bugzilla 8675: Allow throwing 'Throwable' object even if mustNotThrow.
|
||||
result = BEfallthru;
|
||||
return;
|
||||
}
|
||||
|
||||
Type *t = s->exp->type->toBasetype();
|
||||
ClassDeclaration *cd = t->isClassHandle();
|
||||
assert(cd);
|
||||
|
||||
if (cd == ClassDeclaration::errorException ||
|
||||
ClassDeclaration::errorException->isBaseOf(cd, NULL))
|
||||
{
|
||||
result = BEerrthrow;
|
||||
return;
|
||||
}
|
||||
if (mustNotThrow)
|
||||
s->error("%s is thrown but not caught", s->exp->type->toChars());
|
||||
|
||||
result = BEthrow;
|
||||
}
|
||||
|
||||
void visit(GotoStatement *)
|
||||
{
|
||||
//printf("GotoStatement::blockExit(%p)\n", s);
|
||||
result = BEgoto;
|
||||
}
|
||||
|
||||
void visit(LabelStatement *s)
|
||||
{
|
||||
//printf("LabelStatement::blockExit(%p)\n", s);
|
||||
result = s->statement ? blockExit(s->statement, func, mustNotThrow) : BEfallthru;
|
||||
if (s->breaks)
|
||||
result |= BEfallthru;
|
||||
}
|
||||
|
||||
void visit(CompoundAsmStatement *s)
|
||||
{
|
||||
if (mustNotThrow && !(s->stc & STCnothrow))
|
||||
s->deprecation("asm statement is assumed to throw - mark it with `nothrow` if it does not");
|
||||
|
||||
// Assume the worst
|
||||
result = BEfallthru | BEreturn | BEgoto | BEhalt;
|
||||
if (!(s->stc & STCnothrow)) result |= BEthrow;
|
||||
}
|
||||
|
||||
void visit(ImportStatement *)
|
||||
{
|
||||
result = BEfallthru;
|
||||
}
|
||||
};
|
||||
|
||||
if (!s)
|
||||
return BEfallthru;
|
||||
BlockExit be(func, mustNotThrow);
|
||||
s->accept(&be);
|
||||
return be.result;
|
||||
}
|
537
gcc/d/dmd/blockexit.d
Normal file
537
gcc/d/dmd/blockexit.d
Normal file
|
@ -0,0 +1,537 @@
|
|||
/**
|
||||
* Find out in what ways control flow can exit a statement block.
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/blockexit.d, _blockexit.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_blockexit.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/blockexit.d
|
||||
*/
|
||||
|
||||
module dmd.blockexit;
|
||||
|
||||
import core.stdc.stdio;
|
||||
|
||||
import dmd.arraytypes;
|
||||
import dmd.astenums;
|
||||
import dmd.canthrow;
|
||||
import dmd.dclass;
|
||||
import dmd.declaration;
|
||||
import dmd.expression;
|
||||
import dmd.func;
|
||||
import dmd.globals;
|
||||
import dmd.id;
|
||||
import dmd.identifier;
|
||||
import dmd.mtype;
|
||||
import dmd.statement;
|
||||
import dmd.tokens;
|
||||
import dmd.visitor;
|
||||
|
||||
/**
|
||||
* BE stands for BlockExit.
|
||||
*
|
||||
* It indicates if a statement does transfer control to another block.
|
||||
* A block is a sequence of statements enclosed in { }
|
||||
*/
|
||||
enum BE : int
|
||||
{
|
||||
none = 0,
|
||||
fallthru = 1,
|
||||
throw_ = 2,
|
||||
return_ = 4,
|
||||
goto_ = 8,
|
||||
halt = 0x10,
|
||||
break_ = 0x20,
|
||||
continue_ = 0x40,
|
||||
errthrow = 0x80,
|
||||
any = (fallthru | throw_ | return_ | goto_ | halt),
|
||||
}
|
||||
|
||||
|
||||
/*********************************************
|
||||
* Determine mask of ways that a statement can exit.
|
||||
*
|
||||
* Only valid after semantic analysis.
|
||||
* Params:
|
||||
* s = statement to check for block exit status
|
||||
* func = function that statement s is in
|
||||
* mustNotThrow = generate an error if it throws
|
||||
* Returns:
|
||||
* BE.xxxx
|
||||
*/
|
||||
int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
|
||||
{
|
||||
extern (C++) final class BlockExit : Visitor
|
||||
{
|
||||
alias visit = Visitor.visit;
|
||||
public:
|
||||
FuncDeclaration func;
|
||||
bool mustNotThrow;
|
||||
int result;
|
||||
|
||||
extern (D) this(FuncDeclaration func, bool mustNotThrow)
|
||||
{
|
||||
this.func = func;
|
||||
this.mustNotThrow = mustNotThrow;
|
||||
result = BE.none;
|
||||
}
|
||||
|
||||
override void visit(Statement s)
|
||||
{
|
||||
printf("Statement::blockExit(%p)\n", s);
|
||||
printf("%s\n", s.toChars());
|
||||
assert(0);
|
||||
}
|
||||
|
||||
override void visit(ErrorStatement s)
|
||||
{
|
||||
result = BE.none;
|
||||
}
|
||||
|
||||
override void visit(ExpStatement s)
|
||||
{
|
||||
result = BE.fallthru;
|
||||
if (s.exp)
|
||||
{
|
||||
if (s.exp.op == TOK.halt)
|
||||
{
|
||||
result = BE.halt;
|
||||
return;
|
||||
}
|
||||
if (s.exp.op == TOK.assert_)
|
||||
{
|
||||
AssertExp a = cast(AssertExp)s.exp;
|
||||
if (a.e1.isBool(false)) // if it's an assert(0)
|
||||
{
|
||||
result = BE.halt;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (s.exp.type.toBasetype().isTypeNoreturn())
|
||||
result = BE.halt;
|
||||
if (canThrow(s.exp, func, mustNotThrow))
|
||||
result |= BE.throw_;
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(CompileStatement s)
|
||||
{
|
||||
assert(global.errors);
|
||||
result = BE.fallthru;
|
||||
}
|
||||
|
||||
override void visit(CompoundStatement cs)
|
||||
{
|
||||
//printf("CompoundStatement.blockExit(%p) %d result = x%X\n", cs, cs.statements.dim, result);
|
||||
result = BE.fallthru;
|
||||
Statement slast = null;
|
||||
foreach (s; *cs.statements)
|
||||
{
|
||||
if (s)
|
||||
{
|
||||
//printf("result = x%x\n", result);
|
||||
//printf("s: %s\n", s.toChars());
|
||||
if (result & BE.fallthru && slast)
|
||||
{
|
||||
slast = slast.last();
|
||||
if (slast && (slast.isCaseStatement() || slast.isDefaultStatement()) && (s.isCaseStatement() || s.isDefaultStatement()))
|
||||
{
|
||||
// Allow if last case/default was empty
|
||||
CaseStatement sc = slast.isCaseStatement();
|
||||
DefaultStatement sd = slast.isDefaultStatement();
|
||||
if (sc && (!sc.statement.hasCode() || sc.statement.isCaseStatement() || sc.statement.isErrorStatement()))
|
||||
{
|
||||
}
|
||||
else if (sd && (!sd.statement.hasCode() || sd.statement.isCaseStatement() || sd.statement.isErrorStatement()))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
const(char)* gototype = s.isCaseStatement() ? "case" : "default";
|
||||
s.deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(result & BE.fallthru) && !s.comeFrom())
|
||||
{
|
||||
if (blockExit(s, func, mustNotThrow) != BE.halt && s.hasCode() &&
|
||||
s.loc != Loc.initial) // don't emit warning for generated code
|
||||
s.warning("statement is not reachable");
|
||||
}
|
||||
else
|
||||
{
|
||||
result &= ~BE.fallthru;
|
||||
result |= blockExit(s, func, mustNotThrow);
|
||||
}
|
||||
slast = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(UnrolledLoopStatement uls)
|
||||
{
|
||||
result = BE.fallthru;
|
||||
foreach (s; *uls.statements)
|
||||
{
|
||||
if (s)
|
||||
{
|
||||
int r = blockExit(s, func, mustNotThrow);
|
||||
result |= r & ~(BE.break_ | BE.continue_ | BE.fallthru);
|
||||
if ((r & (BE.fallthru | BE.continue_ | BE.break_)) == 0)
|
||||
result &= ~BE.fallthru;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(ScopeStatement s)
|
||||
{
|
||||
//printf("ScopeStatement::blockExit(%p)\n", s.statement);
|
||||
result = blockExit(s.statement, func, mustNotThrow);
|
||||
}
|
||||
|
||||
override void visit(WhileStatement s)
|
||||
{
|
||||
assert(global.errors);
|
||||
result = BE.fallthru;
|
||||
}
|
||||
|
||||
override void visit(DoStatement s)
|
||||
{
|
||||
if (s._body)
|
||||
{
|
||||
result = blockExit(s._body, func, mustNotThrow);
|
||||
if (result == BE.break_)
|
||||
{
|
||||
result = BE.fallthru;
|
||||
return;
|
||||
}
|
||||
if (result & BE.continue_)
|
||||
result |= BE.fallthru;
|
||||
}
|
||||
else
|
||||
result = BE.fallthru;
|
||||
if (result & BE.fallthru)
|
||||
{
|
||||
if (canThrow(s.condition, func, mustNotThrow))
|
||||
result |= BE.throw_;
|
||||
if (!(result & BE.break_) && s.condition.isBool(true))
|
||||
result &= ~BE.fallthru;
|
||||
}
|
||||
result &= ~(BE.break_ | BE.continue_);
|
||||
}
|
||||
|
||||
override void visit(ForStatement s)
|
||||
{
|
||||
result = BE.fallthru;
|
||||
if (s._init)
|
||||
{
|
||||
result = blockExit(s._init, func, mustNotThrow);
|
||||
if (!(result & BE.fallthru))
|
||||
return;
|
||||
}
|
||||
if (s.condition)
|
||||
{
|
||||
if (canThrow(s.condition, func, mustNotThrow))
|
||||
result |= BE.throw_;
|
||||
if (s.condition.isBool(true))
|
||||
result &= ~BE.fallthru;
|
||||
else if (s.condition.isBool(false))
|
||||
return;
|
||||
}
|
||||
else
|
||||
result &= ~BE.fallthru; // the body must do the exiting
|
||||
if (s._body)
|
||||
{
|
||||
int r = blockExit(s._body, func, mustNotThrow);
|
||||
if (r & (BE.break_ | BE.goto_))
|
||||
result |= BE.fallthru;
|
||||
result |= r & ~(BE.fallthru | BE.break_ | BE.continue_);
|
||||
}
|
||||
if (s.increment && canThrow(s.increment, func, mustNotThrow))
|
||||
result |= BE.throw_;
|
||||
}
|
||||
|
||||
override void visit(ForeachStatement s)
|
||||
{
|
||||
result = BE.fallthru;
|
||||
if (canThrow(s.aggr, func, mustNotThrow))
|
||||
result |= BE.throw_;
|
||||
if (s._body)
|
||||
result |= blockExit(s._body, func, mustNotThrow) & ~(BE.break_ | BE.continue_);
|
||||
}
|
||||
|
||||
override void visit(ForeachRangeStatement s)
|
||||
{
|
||||
assert(global.errors);
|
||||
result = BE.fallthru;
|
||||
}
|
||||
|
||||
override void visit(IfStatement s)
|
||||
{
|
||||
//printf("IfStatement::blockExit(%p)\n", s);
|
||||
result = BE.none;
|
||||
if (canThrow(s.condition, func, mustNotThrow))
|
||||
result |= BE.throw_;
|
||||
if (s.condition.isBool(true))
|
||||
{
|
||||
result |= blockExit(s.ifbody, func, mustNotThrow);
|
||||
}
|
||||
else if (s.condition.isBool(false))
|
||||
{
|
||||
result |= blockExit(s.elsebody, func, mustNotThrow);
|
||||
}
|
||||
else
|
||||
{
|
||||
result |= blockExit(s.ifbody, func, mustNotThrow);
|
||||
result |= blockExit(s.elsebody, func, mustNotThrow);
|
||||
}
|
||||
//printf("IfStatement::blockExit(%p) = x%x\n", s, result);
|
||||
}
|
||||
|
||||
override void visit(ConditionalStatement s)
|
||||
{
|
||||
result = blockExit(s.ifbody, func, mustNotThrow);
|
||||
if (s.elsebody)
|
||||
result |= blockExit(s.elsebody, func, mustNotThrow);
|
||||
}
|
||||
|
||||
override void visit(PragmaStatement s)
|
||||
{
|
||||
result = BE.fallthru;
|
||||
}
|
||||
|
||||
override void visit(StaticAssertStatement s)
|
||||
{
|
||||
result = BE.fallthru;
|
||||
}
|
||||
|
||||
override void visit(SwitchStatement s)
|
||||
{
|
||||
result = BE.none;
|
||||
if (canThrow(s.condition, func, mustNotThrow))
|
||||
result |= BE.throw_;
|
||||
if (s._body)
|
||||
{
|
||||
result |= blockExit(s._body, func, mustNotThrow);
|
||||
if (result & BE.break_)
|
||||
{
|
||||
result |= BE.fallthru;
|
||||
result &= ~BE.break_;
|
||||
}
|
||||
}
|
||||
else
|
||||
result |= BE.fallthru;
|
||||
}
|
||||
|
||||
override void visit(CaseStatement s)
|
||||
{
|
||||
result = blockExit(s.statement, func, mustNotThrow);
|
||||
}
|
||||
|
||||
override void visit(DefaultStatement s)
|
||||
{
|
||||
result = blockExit(s.statement, func, mustNotThrow);
|
||||
}
|
||||
|
||||
override void visit(GotoDefaultStatement s)
|
||||
{
|
||||
result = BE.goto_;
|
||||
}
|
||||
|
||||
override void visit(GotoCaseStatement s)
|
||||
{
|
||||
result = BE.goto_;
|
||||
}
|
||||
|
||||
override void visit(SwitchErrorStatement s)
|
||||
{
|
||||
// Switch errors are non-recoverable
|
||||
result = BE.halt;
|
||||
}
|
||||
|
||||
override void visit(ReturnStatement s)
|
||||
{
|
||||
result = BE.return_;
|
||||
if (s.exp && canThrow(s.exp, func, mustNotThrow))
|
||||
result |= BE.throw_;
|
||||
}
|
||||
|
||||
override void visit(BreakStatement s)
|
||||
{
|
||||
//printf("BreakStatement::blockExit(%p) = x%x\n", s, s.ident ? BE.goto_ : BE.break_);
|
||||
result = s.ident ? BE.goto_ : BE.break_;
|
||||
}
|
||||
|
||||
override void visit(ContinueStatement s)
|
||||
{
|
||||
result = s.ident ? BE.continue_ | BE.goto_ : BE.continue_;
|
||||
}
|
||||
|
||||
override void visit(SynchronizedStatement s)
|
||||
{
|
||||
result = blockExit(s._body, func, mustNotThrow);
|
||||
}
|
||||
|
||||
override void visit(WithStatement s)
|
||||
{
|
||||
result = BE.none;
|
||||
if (canThrow(s.exp, func, mustNotThrow))
|
||||
result = BE.throw_;
|
||||
result |= blockExit(s._body, func, mustNotThrow);
|
||||
}
|
||||
|
||||
override void visit(TryCatchStatement s)
|
||||
{
|
||||
assert(s._body);
|
||||
result = blockExit(s._body, func, false);
|
||||
|
||||
int catchresult = 0;
|
||||
foreach (c; *s.catches)
|
||||
{
|
||||
if (c.type == Type.terror)
|
||||
continue;
|
||||
|
||||
int cresult = blockExit(c.handler, func, mustNotThrow);
|
||||
|
||||
/* If we're catching Object, then there is no throwing
|
||||
*/
|
||||
Identifier id = c.type.toBasetype().isClassHandle().ident;
|
||||
if (c.internalCatch && (cresult & BE.fallthru))
|
||||
{
|
||||
// https://issues.dlang.org/show_bug.cgi?id=11542
|
||||
// leave blockExit flags of the body
|
||||
cresult &= ~BE.fallthru;
|
||||
}
|
||||
else if (id == Id.Object || id == Id.Throwable)
|
||||
{
|
||||
result &= ~(BE.throw_ | BE.errthrow);
|
||||
}
|
||||
else if (id == Id.Exception)
|
||||
{
|
||||
result &= ~BE.throw_;
|
||||
}
|
||||
catchresult |= cresult;
|
||||
}
|
||||
if (mustNotThrow && (result & BE.throw_))
|
||||
{
|
||||
// now explain why this is nothrow
|
||||
blockExit(s._body, func, mustNotThrow);
|
||||
}
|
||||
result |= catchresult;
|
||||
}
|
||||
|
||||
override void visit(TryFinallyStatement s)
|
||||
{
|
||||
result = BE.fallthru;
|
||||
if (s._body)
|
||||
result = blockExit(s._body, func, false);
|
||||
|
||||
// check finally body as well, it may throw (bug #4082)
|
||||
int finalresult = BE.fallthru;
|
||||
if (s.finalbody)
|
||||
finalresult = blockExit(s.finalbody, func, false);
|
||||
|
||||
// If either body or finalbody halts
|
||||
if (result == BE.halt)
|
||||
finalresult = BE.none;
|
||||
if (finalresult == BE.halt)
|
||||
result = BE.none;
|
||||
|
||||
if (mustNotThrow)
|
||||
{
|
||||
// now explain why this is nothrow
|
||||
if (s._body && (result & BE.throw_))
|
||||
blockExit(s._body, func, mustNotThrow);
|
||||
if (s.finalbody && (finalresult & BE.throw_))
|
||||
blockExit(s.finalbody, func, mustNotThrow);
|
||||
}
|
||||
|
||||
version (none)
|
||||
{
|
||||
// https://issues.dlang.org/show_bug.cgi?id=13201
|
||||
// Mask to prevent spurious warnings for
|
||||
// destructor call, exit of synchronized statement, etc.
|
||||
if (result == BE.halt && finalresult != BE.halt && s.finalbody && s.finalbody.hasCode())
|
||||
{
|
||||
s.finalbody.warning("statement is not reachable");
|
||||
}
|
||||
}
|
||||
|
||||
if (!(finalresult & BE.fallthru))
|
||||
result &= ~BE.fallthru;
|
||||
result |= finalresult & ~BE.fallthru;
|
||||
}
|
||||
|
||||
override void visit(ScopeGuardStatement s)
|
||||
{
|
||||
// At this point, this statement is just an empty placeholder
|
||||
result = BE.fallthru;
|
||||
}
|
||||
|
||||
override void visit(ThrowStatement s)
|
||||
{
|
||||
if (s.internalThrow)
|
||||
{
|
||||
// https://issues.dlang.org/show_bug.cgi?id=8675
|
||||
// Allow throwing 'Throwable' object even if mustNotThrow.
|
||||
result = BE.fallthru;
|
||||
return;
|
||||
}
|
||||
|
||||
Type t = s.exp.type.toBasetype();
|
||||
ClassDeclaration cd = t.isClassHandle();
|
||||
assert(cd);
|
||||
|
||||
if (cd == ClassDeclaration.errorException || ClassDeclaration.errorException.isBaseOf(cd, null))
|
||||
{
|
||||
result = BE.errthrow;
|
||||
return;
|
||||
}
|
||||
if (mustNotThrow)
|
||||
s.error("`%s` is thrown but not caught", s.exp.type.toChars());
|
||||
|
||||
result = BE.throw_;
|
||||
}
|
||||
|
||||
override void visit(GotoStatement s)
|
||||
{
|
||||
//printf("GotoStatement::blockExit(%p)\n", s);
|
||||
result = BE.goto_;
|
||||
}
|
||||
|
||||
override void visit(LabelStatement s)
|
||||
{
|
||||
//printf("LabelStatement::blockExit(%p)\n", s);
|
||||
result = blockExit(s.statement, func, mustNotThrow);
|
||||
if (s.breaks)
|
||||
result |= BE.fallthru;
|
||||
}
|
||||
|
||||
override void visit(CompoundAsmStatement s)
|
||||
{
|
||||
// Assume the worst
|
||||
result = BE.fallthru | BE.return_ | BE.goto_ | BE.halt;
|
||||
if (!(s.stc & STC.nothrow_))
|
||||
{
|
||||
if (mustNotThrow && !(s.stc & STC.nothrow_))
|
||||
s.deprecation("`asm` statement is assumed to throw - mark it with `nothrow` if it does not");
|
||||
else
|
||||
result |= BE.throw_;
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(ImportStatement s)
|
||||
{
|
||||
result = BE.fallthru;
|
||||
}
|
||||
}
|
||||
|
||||
if (!s)
|
||||
return BE.fallthru;
|
||||
scope BlockExit be = new BlockExit(func, mustNotThrow);
|
||||
s.accept(be);
|
||||
return be.result;
|
||||
}
|
||||
|
33
gcc/d/dmd/builtin.d
Normal file
33
gcc/d/dmd/builtin.d
Normal file
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* Implement CTFE for intrinsic (builtin) functions.
|
||||
*
|
||||
* Currently includes functions from `std.math`, `core.math` and `core.bitop`.
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/builtin.d, _builtin.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_builtin.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/builtin.d
|
||||
*/
|
||||
|
||||
module dmd.builtin;
|
||||
|
||||
import core.stdc.math;
|
||||
import core.stdc.string;
|
||||
import dmd.arraytypes;
|
||||
import dmd.expression;
|
||||
import dmd.func;
|
||||
import dmd.globals;
|
||||
|
||||
/**********************************
|
||||
* Determine if function is a builtin one that we can
|
||||
* evaluate at compile time.
|
||||
*/
|
||||
public extern (C++) BUILTIN isBuiltin(FuncDeclaration fd);
|
||||
|
||||
/**************************************
|
||||
* Evaluate builtin function.
|
||||
* Return result; NULL if cannot evaluate it.
|
||||
*/
|
||||
public extern (C++) Expression eval_builtin(Loc loc, FuncDeclaration fd, Expressions* arguments);
|
|
@ -1,316 +0,0 @@
|
|||
|
||||
/* Compiler implementation of the D programming language
|
||||
* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/D-Programming-Language/dmd/blob/master/src/canthrow.c
|
||||
*/
|
||||
|
||||
#include "root/dsystem.h"
|
||||
|
||||
#include "mars.h"
|
||||
#include "init.h"
|
||||
#include "expression.h"
|
||||
#include "template.h"
|
||||
#include "statement.h"
|
||||
#include "mtype.h"
|
||||
#include "utf.h"
|
||||
#include "declaration.h"
|
||||
#include "aggregate.h"
|
||||
#include "scope.h"
|
||||
#include "attrib.h"
|
||||
#include "tokens.h"
|
||||
|
||||
bool Dsymbol_canThrow(Dsymbol *s, FuncDeclaration *func, bool mustNotThrow);
|
||||
bool walkPostorder(Expression *e, StoppableVisitor *v);
|
||||
|
||||
/********************************************
|
||||
* Returns true if the expression may throw exceptions.
|
||||
* If 'mustNotThrow' is true, generate an error if it throws
|
||||
*/
|
||||
|
||||
bool canThrow(Expression *e, FuncDeclaration *func, bool mustNotThrow)
|
||||
{
|
||||
//printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars());
|
||||
|
||||
// stop walking if we determine this expression can throw
|
||||
class CanThrow : public StoppableVisitor
|
||||
{
|
||||
FuncDeclaration *func;
|
||||
bool mustNotThrow;
|
||||
|
||||
public:
|
||||
CanThrow(FuncDeclaration *func, bool mustNotThrow)
|
||||
: func(func), mustNotThrow(mustNotThrow)
|
||||
{
|
||||
}
|
||||
|
||||
void visit(Expression *)
|
||||
{
|
||||
}
|
||||
|
||||
void visit(DeclarationExp *de)
|
||||
{
|
||||
stop = Dsymbol_canThrow(de->declaration, func, mustNotThrow);
|
||||
}
|
||||
|
||||
void visit(CallExp *ce)
|
||||
{
|
||||
if (global.errors && !ce->e1->type)
|
||||
return; // error recovery
|
||||
|
||||
/* If calling a function or delegate that is typed as nothrow,
|
||||
* then this expression cannot throw.
|
||||
* Note that pure functions can throw.
|
||||
*/
|
||||
Type *t = ce->e1->type->toBasetype();
|
||||
if (ce->f && ce->f == func)
|
||||
return;
|
||||
if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow)
|
||||
return;
|
||||
if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow)
|
||||
return;
|
||||
|
||||
if (mustNotThrow)
|
||||
{
|
||||
if (ce->f)
|
||||
{
|
||||
ce->error("%s `%s` is not nothrow",
|
||||
ce->f->kind(), ce->f->toPrettyChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
Expression *e1 = ce->e1;
|
||||
if (e1->op == TOKstar) // print 'fp' if e1 is (*fp)
|
||||
e1 = ((PtrExp *)e1)->e1;
|
||||
ce->error("`%s` is not nothrow", e1->toChars());
|
||||
}
|
||||
}
|
||||
stop = true;
|
||||
}
|
||||
|
||||
void visit(NewExp *ne)
|
||||
{
|
||||
if (ne->member)
|
||||
{
|
||||
if (ne->allocator)
|
||||
{
|
||||
// Bugzilla 14407
|
||||
Type *t = ne->allocator->type->toBasetype();
|
||||
if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
|
||||
{
|
||||
if (mustNotThrow)
|
||||
{
|
||||
ne->error("%s `%s` is not nothrow",
|
||||
ne->allocator->kind(), ne->allocator->toPrettyChars());
|
||||
}
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
// See if constructor call can throw
|
||||
Type *t = ne->member->type->toBasetype();
|
||||
if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
|
||||
{
|
||||
if (mustNotThrow)
|
||||
{
|
||||
ne->error("%s `%s` is not nothrow",
|
||||
ne->member->kind(), ne->member->toPrettyChars());
|
||||
}
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
// regard storage allocation failures as not recoverable
|
||||
}
|
||||
|
||||
void visit(DeleteExp *de)
|
||||
{
|
||||
Type *tb = de->e1->type->toBasetype();
|
||||
AggregateDeclaration *ad = NULL;
|
||||
switch (tb->ty)
|
||||
{
|
||||
case Tclass:
|
||||
ad = ((TypeClass *)tb)->sym;
|
||||
break;
|
||||
|
||||
case Tpointer:
|
||||
tb = ((TypePointer *)tb)->next->toBasetype();
|
||||
if (tb->ty == Tstruct)
|
||||
ad = ((TypeStruct *)tb)->sym;
|
||||
break;
|
||||
|
||||
case Tarray:
|
||||
{
|
||||
Type *tv = tb->nextOf()->baseElemOf();
|
||||
if (tv->ty == Tstruct)
|
||||
{
|
||||
ad = ((TypeStruct *)tv)->sym;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!ad)
|
||||
return;
|
||||
|
||||
if (ad->dtor)
|
||||
{
|
||||
Type *t = ad->dtor->type->toBasetype();
|
||||
if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
|
||||
{
|
||||
if (mustNotThrow)
|
||||
{
|
||||
de->error("%s `%s` is not nothrow",
|
||||
ad->dtor->kind(), ad->dtor->toPrettyChars());
|
||||
}
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
if (ad->aggDelete && tb->ty != Tarray)
|
||||
{
|
||||
Type *t = ad->aggDelete->type;
|
||||
if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
|
||||
{
|
||||
if (mustNotThrow)
|
||||
{
|
||||
de->error("%s `%s` is not nothrow",
|
||||
ad->aggDelete->kind(), ad->aggDelete->toPrettyChars());
|
||||
}
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void visit(AssignExp *ae)
|
||||
{
|
||||
// blit-init cannot throw
|
||||
if (ae->op == TOKblit)
|
||||
return;
|
||||
|
||||
/* Element-wise assignment could invoke postblits.
|
||||
*/
|
||||
Type *t;
|
||||
if (ae->type->toBasetype()->ty == Tsarray)
|
||||
{
|
||||
if (!ae->e2->isLvalue())
|
||||
return;
|
||||
t = ae->type;
|
||||
}
|
||||
else if (ae->e1->op == TOKslice)
|
||||
t = ((SliceExp *)ae->e1)->e1->type;
|
||||
else
|
||||
return;
|
||||
|
||||
Type *tv = t->baseElemOf();
|
||||
if (tv->ty != Tstruct)
|
||||
return;
|
||||
StructDeclaration *sd = ((TypeStruct *)tv)->sym;
|
||||
if (!sd->postblit || sd->postblit->type->ty != Tfunction)
|
||||
return;
|
||||
|
||||
if (((TypeFunction *)sd->postblit->type)->isnothrow)
|
||||
;
|
||||
else
|
||||
{
|
||||
if (mustNotThrow)
|
||||
{
|
||||
ae->error("%s `%s` is not nothrow",
|
||||
sd->postblit->kind(), sd->postblit->toPrettyChars());
|
||||
}
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
void visit(NewAnonClassExp *)
|
||||
{
|
||||
assert(0); // should have been lowered by semantic()
|
||||
}
|
||||
};
|
||||
|
||||
CanThrow ct(func, mustNotThrow);
|
||||
return walkPostorder(e, &ct);
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* Does symbol, when initialized, throw?
|
||||
* Mirrors logic in Dsymbol_toElem().
|
||||
*/
|
||||
|
||||
bool Dsymbol_canThrow(Dsymbol *s, FuncDeclaration *func, bool mustNotThrow)
|
||||
{
|
||||
AttribDeclaration *ad;
|
||||
VarDeclaration *vd;
|
||||
TemplateMixin *tm;
|
||||
TupleDeclaration *td;
|
||||
|
||||
//printf("Dsymbol_toElem() %s\n", s->toChars());
|
||||
ad = s->isAttribDeclaration();
|
||||
if (ad)
|
||||
{
|
||||
Dsymbols *decl = ad->include(NULL);
|
||||
if (decl && decl->length)
|
||||
{
|
||||
for (size_t i = 0; i < decl->length; i++)
|
||||
{
|
||||
s = (*decl)[i];
|
||||
if (Dsymbol_canThrow(s, func, mustNotThrow))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((vd = s->isVarDeclaration()) != NULL)
|
||||
{
|
||||
s = s->toAlias();
|
||||
if (s != vd)
|
||||
return Dsymbol_canThrow(s, func, mustNotThrow);
|
||||
if (vd->storage_class & STCmanifest)
|
||||
;
|
||||
else if (vd->isStatic() || vd->storage_class & (STCextern | STCtls | STCgshared))
|
||||
;
|
||||
else
|
||||
{
|
||||
if (vd->_init)
|
||||
{
|
||||
ExpInitializer *ie = vd->_init->isExpInitializer();
|
||||
if (ie && canThrow(ie->exp, func, mustNotThrow))
|
||||
return true;
|
||||
}
|
||||
if (vd->needsScopeDtor())
|
||||
return canThrow(vd->edtor, func, mustNotThrow);
|
||||
}
|
||||
}
|
||||
else if ((tm = s->isTemplateMixin()) != NULL)
|
||||
{
|
||||
//printf("%s\n", tm->toChars());
|
||||
if (tm->members)
|
||||
{
|
||||
for (size_t i = 0; i < tm->members->length; i++)
|
||||
{
|
||||
Dsymbol *sm = (*tm->members)[i];
|
||||
if (Dsymbol_canThrow(sm, func, mustNotThrow))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((td = s->isTupleDeclaration()) != NULL)
|
||||
{
|
||||
for (size_t i = 0; i < td->objects->length; i++)
|
||||
{
|
||||
RootObject *o = (*td->objects)[i];
|
||||
if (o->dyncast() == DYNCAST_EXPRESSION)
|
||||
{
|
||||
Expression *eo = (Expression *)o;
|
||||
if (eo->op == TOKdsymbol)
|
||||
{
|
||||
DsymbolExp *se = (DsymbolExp *)eo;
|
||||
if (Dsymbol_canThrow(se->s, func, mustNotThrow))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
244
gcc/d/dmd/canthrow.d
Normal file
244
gcc/d/dmd/canthrow.d
Normal file
|
@ -0,0 +1,244 @@
|
|||
/**
|
||||
* Perform checks for `nothrow`.
|
||||
*
|
||||
* Specification: $(LINK2 https://dlang.org/spec/function.html#nothrow-functions, Nothrow Functions)
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/canthrow.d, _canthrow.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_canthrow.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/canthrow.d
|
||||
*/
|
||||
|
||||
module dmd.canthrow;
|
||||
|
||||
import dmd.aggregate;
|
||||
import dmd.apply;
|
||||
import dmd.arraytypes;
|
||||
import dmd.attrib;
|
||||
import dmd.astenums;
|
||||
import dmd.declaration;
|
||||
import dmd.dsymbol;
|
||||
import dmd.expression;
|
||||
import dmd.func;
|
||||
import dmd.globals;
|
||||
import dmd.init;
|
||||
import dmd.mtype;
|
||||
import dmd.root.rootobject;
|
||||
import dmd.tokens;
|
||||
import dmd.visitor;
|
||||
|
||||
/********************************************
|
||||
* Returns true if the expression may throw exceptions.
|
||||
* If 'mustNotThrow' is true, generate an error if it throws
|
||||
*/
|
||||
extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow)
|
||||
{
|
||||
//printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars());
|
||||
// stop walking if we determine this expression can throw
|
||||
extern (C++) final class CanThrow : StoppableVisitor
|
||||
{
|
||||
alias visit = typeof(super).visit;
|
||||
FuncDeclaration func;
|
||||
bool mustNotThrow;
|
||||
|
||||
public:
|
||||
extern (D) this(FuncDeclaration func, bool mustNotThrow)
|
||||
{
|
||||
this.func = func;
|
||||
this.mustNotThrow = mustNotThrow;
|
||||
}
|
||||
|
||||
void checkFuncThrows(Expression e, FuncDeclaration f)
|
||||
{
|
||||
auto tf = f.type.toBasetype().isTypeFunction();
|
||||
if (tf && !tf.isnothrow)
|
||||
{
|
||||
if (mustNotThrow)
|
||||
{
|
||||
e.error("%s `%s` is not `nothrow`",
|
||||
f.kind(), f.toPrettyChars());
|
||||
|
||||
e.checkOverridenDtor(null, f, dd => dd.type.toTypeFunction().isnothrow, "not nothrow");
|
||||
}
|
||||
stop = true; // if any function throws, then the whole expression throws
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(Expression)
|
||||
{
|
||||
}
|
||||
|
||||
override void visit(DeclarationExp de)
|
||||
{
|
||||
stop = Dsymbol_canThrow(de.declaration, func, mustNotThrow);
|
||||
}
|
||||
|
||||
override void visit(CallExp ce)
|
||||
{
|
||||
if (ce.inDebugStatement)
|
||||
return;
|
||||
|
||||
if (global.errors && !ce.e1.type)
|
||||
return; // error recovery
|
||||
/* If calling a function or delegate that is typed as nothrow,
|
||||
* then this expression cannot throw.
|
||||
* Note that pure functions can throw.
|
||||
*/
|
||||
if (ce.f && ce.f == func)
|
||||
return;
|
||||
Type t = ce.e1.type.toBasetype();
|
||||
auto tf = t.isTypeFunction();
|
||||
if (tf && tf.isnothrow)
|
||||
return;
|
||||
else
|
||||
{
|
||||
auto td = t.isTypeDelegate();
|
||||
if (td && td.nextOf().isTypeFunction().isnothrow)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ce.f)
|
||||
checkFuncThrows(ce, ce.f);
|
||||
else if (mustNotThrow)
|
||||
{
|
||||
auto e1 = ce.e1;
|
||||
if (auto pe = e1.isPtrExp()) // print 'fp' if e1 is (*fp)
|
||||
e1 = pe.e1;
|
||||
ce.error("`%s` is not `nothrow`", e1.toChars());
|
||||
}
|
||||
stop = true;
|
||||
}
|
||||
|
||||
override void visit(NewExp ne)
|
||||
{
|
||||
if (ne.member)
|
||||
{
|
||||
// See if constructor call can throw
|
||||
checkFuncThrows(ne, ne.member);
|
||||
}
|
||||
// regard storage allocation failures as not recoverable
|
||||
}
|
||||
|
||||
override void visit(DeleteExp de)
|
||||
{
|
||||
Type tb = de.e1.type.toBasetype();
|
||||
AggregateDeclaration ad = null;
|
||||
switch (tb.ty)
|
||||
{
|
||||
case Tclass:
|
||||
ad = tb.isTypeClass().sym;
|
||||
break;
|
||||
|
||||
case Tpointer:
|
||||
case Tarray:
|
||||
auto ts = tb.nextOf().baseElemOf().isTypeStruct();
|
||||
if (!ts)
|
||||
return;
|
||||
ad = ts.sym;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0); // error should have been detected by semantic()
|
||||
}
|
||||
|
||||
if (ad.dtor)
|
||||
checkFuncThrows(de, ad.dtor);
|
||||
}
|
||||
|
||||
override void visit(AssignExp ae)
|
||||
{
|
||||
// blit-init cannot throw
|
||||
if (ae.op == TOK.blit)
|
||||
return;
|
||||
/* Element-wise assignment could invoke postblits.
|
||||
*/
|
||||
Type t;
|
||||
if (ae.type.toBasetype().ty == Tsarray)
|
||||
{
|
||||
if (!ae.e2.isLvalue())
|
||||
return;
|
||||
t = ae.type;
|
||||
}
|
||||
else if (auto se = ae.e1.isSliceExp())
|
||||
t = se.e1.type;
|
||||
else
|
||||
return;
|
||||
|
||||
if (auto ts = t.baseElemOf().isTypeStruct())
|
||||
if (auto postblit = ts.sym.postblit)
|
||||
checkFuncThrows(ae, postblit);
|
||||
}
|
||||
|
||||
override void visit(NewAnonClassExp)
|
||||
{
|
||||
assert(0); // should have been lowered by semantic()
|
||||
}
|
||||
}
|
||||
|
||||
scope CanThrow ct = new CanThrow(func, mustNotThrow);
|
||||
return walkPostorder(e, ct);
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* Does symbol, when initialized, throw?
|
||||
* Mirrors logic in Dsymbol_toElem().
|
||||
*/
|
||||
private bool Dsymbol_canThrow(Dsymbol s, FuncDeclaration func, bool mustNotThrow)
|
||||
{
|
||||
int symbolDg(Dsymbol s)
|
||||
{
|
||||
return Dsymbol_canThrow(s, func, mustNotThrow);
|
||||
}
|
||||
|
||||
//printf("Dsymbol_toElem() %s\n", s.toChars());
|
||||
if (auto vd = s.isVarDeclaration())
|
||||
{
|
||||
s = s.toAlias();
|
||||
if (s != vd)
|
||||
return Dsymbol_canThrow(s, func, mustNotThrow);
|
||||
if (vd.storage_class & STC.manifest)
|
||||
{
|
||||
}
|
||||
else if (vd.isStatic() || vd.storage_class & (STC.extern_ | STC.tls | STC.gshared))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vd._init)
|
||||
{
|
||||
if (auto ie = vd._init.isExpInitializer())
|
||||
if (canThrow(ie.exp, func, mustNotThrow))
|
||||
return true;
|
||||
}
|
||||
if (vd.needsScopeDtor())
|
||||
return canThrow(vd.edtor, func, mustNotThrow);
|
||||
}
|
||||
}
|
||||
else if (auto ad = s.isAttribDeclaration())
|
||||
{
|
||||
return ad.include(null).foreachDsymbol(&symbolDg) != 0;
|
||||
}
|
||||
else if (auto tm = s.isTemplateMixin())
|
||||
{
|
||||
return tm.members.foreachDsymbol(&symbolDg) != 0;
|
||||
}
|
||||
else if (auto td = s.isTupleDeclaration())
|
||||
{
|
||||
for (size_t i = 0; i < td.objects.dim; i++)
|
||||
{
|
||||
RootObject o = (*td.objects)[i];
|
||||
if (o.dyncast() == DYNCAST.expression)
|
||||
{
|
||||
Expression eo = cast(Expression)o;
|
||||
if (auto se = eo.isDsymbolExp())
|
||||
{
|
||||
if (Dsymbol_canThrow(se.s, func, mustNotThrow))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -1,985 +0,0 @@
|
|||
|
||||
/* Compiler implementation of the D programming language
|
||||
* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
*/
|
||||
|
||||
// Check the arguments to `printf` and `scanf` against the `format` string.
|
||||
|
||||
#include "root/dsystem.h"
|
||||
#include "root/dcompat.h"
|
||||
|
||||
#include "arraytypes.h"
|
||||
#include "cond.h"
|
||||
#include "errors.h"
|
||||
#include "expression.h"
|
||||
#include "globals.h"
|
||||
#include "identifier.h"
|
||||
#include "mtype.h"
|
||||
#include "target.h"
|
||||
|
||||
|
||||
/* Different kinds of formatting specifications, variations we don't
|
||||
care about are merged. (Like we don't care about the difference between
|
||||
f, e, g, a, etc.)
|
||||
|
||||
For `scanf`, every format is a pointer.
|
||||
*/
|
||||
enum Format
|
||||
{
|
||||
Format_d, // int
|
||||
Format_hhd, // signed char
|
||||
Format_hd, // short int
|
||||
Format_ld, // long int
|
||||
Format_lld, // long long int
|
||||
Format_jd, // intmax_t
|
||||
Format_zd, // size_t
|
||||
Format_td, // ptrdiff_t
|
||||
Format_u, // unsigned int
|
||||
Format_hhu, // unsigned char
|
||||
Format_hu, // unsigned short int
|
||||
Format_lu, // unsigned long int
|
||||
Format_llu, // unsigned long long int
|
||||
Format_ju, // uintmax_t
|
||||
Format_g, // float (scanf) / double (printf)
|
||||
Format_lg, // double (scanf)
|
||||
Format_Lg, // long double (both)
|
||||
Format_s, // char string (both)
|
||||
Format_ls, // wchar_t string (both)
|
||||
Format_c, // char (printf)
|
||||
Format_lc, // wint_t (printf)
|
||||
Format_p, // pointer
|
||||
Format_n, // pointer to int
|
||||
Format_hhn, // pointer to signed char
|
||||
Format_hn, // pointer to short
|
||||
Format_ln, // pointer to long int
|
||||
Format_lln, // pointer to long long int
|
||||
Format_jn, // pointer to intmax_t
|
||||
Format_zn, // pointer to size_t
|
||||
Format_tn, // pointer to ptrdiff_t
|
||||
Format_GNU_a, // GNU ext. : address to a string with no maximum size (scanf)
|
||||
Format_GNU_m, // GNU ext. : string corresponding to the error code in errno (printf) / length modifier (scanf)
|
||||
Format_percent, // %% (i.e. no argument)
|
||||
Format_error, // invalid format specification
|
||||
};
|
||||
|
||||
/**************************************
|
||||
* Parse the *length specifier* and the *specifier* of the following form:
|
||||
* `[length]specifier`
|
||||
*
|
||||
* Params:
|
||||
* format = format string
|
||||
* idx = index of of start of format specifier,
|
||||
* which gets updated to index past the end of it,
|
||||
* even if `Format_error` is returned
|
||||
* genSpecifier = Generic specifier. For instance, it will be set to `d` if the
|
||||
* format is `hdd`.
|
||||
* Returns:
|
||||
* Format
|
||||
*/
|
||||
static Format parseGenericFormatSpecifier(const char *format,
|
||||
size_t &idx, char &genSpecifier, bool useGNUExts =
|
||||
findCondition(global.versionids, Identifier::idPool("CRuntime_Glibc")))
|
||||
{
|
||||
genSpecifier = 0;
|
||||
|
||||
const size_t length = strlen(format);
|
||||
|
||||
/* Read the `length modifier`
|
||||
*/
|
||||
const char lm = format[idx];
|
||||
bool lm1= false; // if jztL
|
||||
bool lm2= false; // if `hh` or `ll`
|
||||
if (lm == 'j' ||
|
||||
lm == 'z' ||
|
||||
lm == 't' ||
|
||||
lm == 'L')
|
||||
{
|
||||
++idx;
|
||||
if (idx == length)
|
||||
return Format_error;
|
||||
lm1 = true;
|
||||
}
|
||||
else if (lm == 'h' || lm == 'l')
|
||||
{
|
||||
++idx;
|
||||
if (idx == length)
|
||||
return Format_error;
|
||||
lm2 = lm == format[idx];
|
||||
if (lm2)
|
||||
{
|
||||
++idx;
|
||||
if (idx == length)
|
||||
return Format_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the `specifier`
|
||||
*/
|
||||
Format specifier;
|
||||
const char sc = format[idx];
|
||||
genSpecifier = sc;
|
||||
switch (sc)
|
||||
{
|
||||
case 'd':
|
||||
case 'i':
|
||||
if (lm == 'L')
|
||||
specifier = Format_error;
|
||||
else
|
||||
specifier = lm == 'h' && lm2 ? Format_hhd :
|
||||
lm == 'h' ? Format_hd :
|
||||
lm == 'l' && lm2 ? Format_lld :
|
||||
lm == 'l' ? Format_ld :
|
||||
lm == 'j' ? Format_jd :
|
||||
lm == 'z' ? Format_zd :
|
||||
lm == 't' ? Format_td :
|
||||
Format_d;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
case 'o':
|
||||
case 'x':
|
||||
case 'X':
|
||||
if (lm == 'L')
|
||||
specifier = Format_error;
|
||||
else
|
||||
specifier = lm == 'h' && lm2 ? Format_hhu :
|
||||
lm == 'h' ? Format_hu :
|
||||
lm == 'l' && lm2 ? Format_llu :
|
||||
lm == 'l' ? Format_lu :
|
||||
lm == 'j' ? Format_ju :
|
||||
lm == 'z' ? Format_zd :
|
||||
lm == 't' ? Format_td :
|
||||
Format_u;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
if (useGNUExts)
|
||||
{
|
||||
// https://www.gnu.org/software/libc/manual/html_node/Dynamic-String-Input.html
|
||||
specifier = Format_GNU_a;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
|
||||
case 'f':
|
||||
case 'F':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'A':
|
||||
if (lm == 'L')
|
||||
specifier = Format_Lg;
|
||||
else if (lm1 || lm2 || lm == 'h')
|
||||
specifier = Format_error;
|
||||
else
|
||||
specifier = lm == 'l' ? Format_lg : Format_g;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
if (lm1 || lm2 || lm == 'h')
|
||||
specifier = Format_error;
|
||||
else
|
||||
specifier = lm == 'l' ? Format_lc : Format_c;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (lm1 || lm2 || lm == 'h')
|
||||
specifier = Format_error;
|
||||
else
|
||||
specifier = lm == 'l' ? Format_ls : Format_s;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
if (lm1 || lm2 || lm == 'h' || lm == 'l')
|
||||
specifier = Format_error;
|
||||
else
|
||||
specifier = Format_p;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
if (lm == 'L')
|
||||
specifier = Format_error;
|
||||
else
|
||||
specifier = lm == 'l' && lm2 ? Format_lln :
|
||||
lm == 'l' ? Format_ln :
|
||||
lm == 'h' && lm2 ? Format_hhn :
|
||||
lm == 'h' ? Format_hn :
|
||||
lm == 'j' ? Format_jn :
|
||||
lm == 'z' ? Format_zn :
|
||||
lm == 't' ? Format_tn :
|
||||
Format_n;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
if (useGNUExts)
|
||||
{
|
||||
// http://www.gnu.org/software/libc/manual/html_node/Other-Output-Conversions.html
|
||||
specifier = Format_GNU_m;
|
||||
break;
|
||||
}
|
||||
goto Ldefault;
|
||||
|
||||
default:
|
||||
Ldefault:
|
||||
specifier = Format_error;
|
||||
break;
|
||||
}
|
||||
|
||||
++idx;
|
||||
return specifier; // success
|
||||
}
|
||||
|
||||
Format formatError(size_t &idx, size_t i)
|
||||
{
|
||||
idx = i;
|
||||
return Format_error;
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* Parse the *format specifier* which is of the form:
|
||||
*
|
||||
* `%[*][width][length]specifier`
|
||||
*
|
||||
* Params:
|
||||
* format = format string
|
||||
* idx = index of `%` of start of format specifier,
|
||||
* which gets updated to index past the end of it,
|
||||
* even if `Format_error` is returned
|
||||
* asterisk = set if there is a `*` sub-specifier
|
||||
* Returns:
|
||||
* Format
|
||||
*/
|
||||
static Format parseScanfFormatSpecifier(const char *format, size_t &idx,
|
||||
bool &asterisk)
|
||||
{
|
||||
asterisk = false;
|
||||
|
||||
size_t i = idx;
|
||||
assert(format[i] == '%');
|
||||
const size_t length = strlen(format);
|
||||
|
||||
++i;
|
||||
if (i == length)
|
||||
return formatError(idx, i);
|
||||
|
||||
if (format[i] == '%')
|
||||
{
|
||||
idx = i + 1;
|
||||
return Format_percent;
|
||||
}
|
||||
|
||||
// * sub-specifier
|
||||
if (format[i] == '*')
|
||||
{
|
||||
++i;
|
||||
if (i == length)
|
||||
return formatError(idx, i);
|
||||
asterisk = true;
|
||||
}
|
||||
|
||||
// fieldWidth
|
||||
while (isdigit(format[i]))
|
||||
{
|
||||
i++;
|
||||
if (i == length)
|
||||
return formatError(idx, i);
|
||||
}
|
||||
|
||||
/* Read the scanset
|
||||
* A scanset can be anything, so we just check that it is paired
|
||||
*/
|
||||
if (format[i] == '[')
|
||||
{
|
||||
while (i < length)
|
||||
{
|
||||
if (format[i] == ']')
|
||||
break;
|
||||
++i;
|
||||
}
|
||||
|
||||
// no `]` found
|
||||
if (i == length)
|
||||
return formatError(idx, i);
|
||||
|
||||
++i;
|
||||
// no specifier after `]`
|
||||
// it could be mixed with the one above, but then idx won't have the right index
|
||||
if (i == length)
|
||||
return formatError(idx, i);
|
||||
}
|
||||
|
||||
/* Read the specifier
|
||||
*/
|
||||
char genSpec;
|
||||
Format specifier = parseGenericFormatSpecifier(format, i, genSpec);
|
||||
if (specifier == Format_error)
|
||||
return formatError(idx, i);
|
||||
|
||||
idx = i;
|
||||
return specifier; // success
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* Parse the *format specifier* which is of the form:
|
||||
*
|
||||
* `%[flags][field width][.precision][length modifier]specifier`
|
||||
*
|
||||
* Params:
|
||||
* format = format string
|
||||
* idx = index of `%` of start of format specifier,
|
||||
* which gets updated to index past the end of it,
|
||||
* even if `Format_error` is returned
|
||||
* widthStar = set if * for width
|
||||
* precisionStar = set if * for precision
|
||||
* Returns:
|
||||
* Format
|
||||
*/
|
||||
static Format parsePrintfFormatSpecifier(const char *format, size_t &idx,
|
||||
bool &widthStar, bool &precisionStar)
|
||||
{
|
||||
widthStar = false;
|
||||
precisionStar = false;
|
||||
|
||||
size_t i = idx;
|
||||
assert(format[i] == '%');
|
||||
const size_t format_length = strlen(format);
|
||||
const size_t length = format_length;
|
||||
bool hash = false;
|
||||
bool zero = false;
|
||||
bool flags = false;
|
||||
bool width = false;
|
||||
bool precision = false;
|
||||
|
||||
++i;
|
||||
if (i == length)
|
||||
return formatError(idx, i);
|
||||
|
||||
if (format[i] == '%')
|
||||
{
|
||||
idx = i + 1;
|
||||
return Format_percent;
|
||||
}
|
||||
|
||||
/* Read the `flags`
|
||||
*/
|
||||
while (1)
|
||||
{
|
||||
const char c = format[i];
|
||||
if (c == '-' ||
|
||||
c == '+' ||
|
||||
c == ' ')
|
||||
{
|
||||
flags = true;
|
||||
}
|
||||
else if (c == '#')
|
||||
{
|
||||
hash = true;
|
||||
}
|
||||
else if (c == '0')
|
||||
{
|
||||
zero = true;
|
||||
}
|
||||
else
|
||||
break;
|
||||
++i;
|
||||
if (i == length)
|
||||
return formatError(idx, i);
|
||||
}
|
||||
|
||||
/* Read the `field width`
|
||||
*/
|
||||
{
|
||||
const char c = format[i];
|
||||
if (c == '*')
|
||||
{
|
||||
width = true;
|
||||
widthStar = true;
|
||||
++i;
|
||||
if (i == length)
|
||||
return formatError(idx, i);
|
||||
}
|
||||
else if ('1' <= c && c <= '9')
|
||||
{
|
||||
width = true;
|
||||
++i;
|
||||
if (i == length)
|
||||
return formatError(idx, i);
|
||||
while ('0' <= format[i] && format[i] <= '9')
|
||||
{
|
||||
++i;
|
||||
if (i == length)
|
||||
return formatError(idx, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the `precision`
|
||||
*/
|
||||
if (format[i] == '.')
|
||||
{
|
||||
precision = true;
|
||||
++i;
|
||||
if (i == length)
|
||||
return formatError(idx, i);
|
||||
const char c = format[i];
|
||||
if (c == '*')
|
||||
{
|
||||
precisionStar = true;
|
||||
++i;
|
||||
if (i == length)
|
||||
return formatError(idx, i);
|
||||
}
|
||||
else if ('0' <= c && c <= '9')
|
||||
{
|
||||
++i;
|
||||
if (i == length)
|
||||
return formatError(idx, i);
|
||||
while ('0' <= format[i] && format[i] <= '9')
|
||||
{
|
||||
++i;
|
||||
if (i == length)
|
||||
return formatError(idx, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the specifier
|
||||
*/
|
||||
char genSpec;
|
||||
Format specifier = parseGenericFormatSpecifier(format, i, genSpec);
|
||||
if (specifier == Format_error)
|
||||
return formatError(idx, i);
|
||||
|
||||
switch (genSpec)
|
||||
{
|
||||
case 'c':
|
||||
case 's':
|
||||
if (hash || zero)
|
||||
return formatError(idx, i);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
if (hash)
|
||||
return formatError(idx, i);
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
if (hash || zero || precision || width || flags)
|
||||
return formatError(idx, i);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
idx = i;
|
||||
return specifier; // success
|
||||
}
|
||||
|
||||
/*******************************************/
|
||||
|
||||
static Expression *getNextPrintfArg(const Loc &loc, Expressions &args, size_t &n,
|
||||
size_t gnu_m_count, bool &skip)
|
||||
{
|
||||
if (n == args.length)
|
||||
{
|
||||
if (args.length < (n + 1) - gnu_m_count)
|
||||
deprecation(loc, "more format specifiers than %d arguments", (int)n);
|
||||
else
|
||||
skip = true;
|
||||
return NULL;
|
||||
}
|
||||
return args[n++];
|
||||
}
|
||||
|
||||
static void errorPrintfFormat(const char *prefix, DString &slice, Expression *arg,
|
||||
const char *texpect, Type *tactual)
|
||||
{
|
||||
deprecation(arg->loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`",
|
||||
prefix ? prefix : "", arg->toChars(), (int)slice.length, slice.ptr, texpect, tactual->toChars());
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Check that arguments to a printf format string are compatible
|
||||
* with that string. Issue errors for incompatibilities.
|
||||
*
|
||||
* Follows the C99 specification for printf.
|
||||
*
|
||||
* Takes a generous, rather than strict, view of compatiblity.
|
||||
* For example, an unsigned value can be formatted with a signed specifier.
|
||||
*
|
||||
* Diagnosed incompatibilities are:
|
||||
*
|
||||
* 1. incompatible sizes which will cause argument misalignment
|
||||
* 2. deferencing arguments that are not pointers
|
||||
* 3. insufficient number of arguments
|
||||
* 4. struct arguments
|
||||
* 5. array and slice arguments
|
||||
* 6. non-pointer arguments to `s` specifier
|
||||
* 7. non-standard formats
|
||||
* 8. undefined behavior per C99
|
||||
*
|
||||
* Per the C Standard, extra arguments are ignored.
|
||||
*
|
||||
* No attempt is made to fix the arguments or the format string.
|
||||
*
|
||||
* Params:
|
||||
* loc = location for error messages
|
||||
* format = format string
|
||||
* args = arguments to match with format string
|
||||
* isVa_list = if a "v" function (format check only)
|
||||
*
|
||||
* Returns:
|
||||
* `true` if errors occurred
|
||||
* References:
|
||||
* C99 7.19.6.1
|
||||
* http://www.cplusplus.com/reference/cstdio/printf/
|
||||
*/
|
||||
bool checkPrintfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list)
|
||||
{
|
||||
//printf("checkPrintFormat('%s')\n", format);
|
||||
size_t n = 0; // index in args
|
||||
size_t gnu_m_count = 0; // number of Format_GNU_m
|
||||
const size_t format_length = strlen(format);
|
||||
for (size_t i = 0; i < format_length;)
|
||||
{
|
||||
if (format[i] != '%')
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
bool widthStar = false;
|
||||
bool precisionStar = false;
|
||||
size_t j = i;
|
||||
const Format fmt = parsePrintfFormatSpecifier(format, j, widthStar, precisionStar);
|
||||
DString slice = DString(j - i, format + i);
|
||||
i = j;
|
||||
|
||||
if (fmt == Format_percent)
|
||||
continue; // "%%", no arguments
|
||||
|
||||
if (isVa_list)
|
||||
{
|
||||
// format check only
|
||||
if (fmt == Format_error)
|
||||
deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fmt == Format_GNU_m)
|
||||
++gnu_m_count;
|
||||
|
||||
if (widthStar)
|
||||
{
|
||||
bool skip = false;
|
||||
Expression *e = getNextPrintfArg(loc, args, n, gnu_m_count, skip);
|
||||
if (skip)
|
||||
continue;
|
||||
if (!e)
|
||||
return true;
|
||||
Type *t = e->type->toBasetype();
|
||||
if (t->ty != Tint32 && t->ty != Tuns32)
|
||||
errorPrintfFormat("width ", slice, e, "int", t);
|
||||
}
|
||||
|
||||
if (precisionStar)
|
||||
{
|
||||
bool skip = false;
|
||||
Expression *e = getNextPrintfArg(loc, args, n, gnu_m_count, skip);
|
||||
if (skip)
|
||||
continue;
|
||||
if (!e)
|
||||
return true;
|
||||
Type *t = e->type->toBasetype();
|
||||
if (t->ty != Tint32 && t->ty != Tuns32)
|
||||
errorPrintfFormat("precision ", slice, e, "int", t);
|
||||
}
|
||||
|
||||
bool skip = false;
|
||||
Expression *e = getNextPrintfArg(loc, args, n, gnu_m_count, skip);
|
||||
if (skip)
|
||||
continue;
|
||||
if (!e)
|
||||
return true;
|
||||
Type *t = e->type->toBasetype();
|
||||
Type *tnext = t->nextOf();
|
||||
const unsigned c_longsize = target.c.longsize;
|
||||
const unsigned ptrsize = target.ptrsize;
|
||||
|
||||
// Types which are promoted to int are allowed.
|
||||
// Spec: C99 6.5.2.2.7
|
||||
switch (fmt)
|
||||
{
|
||||
case Format_u: // unsigned int
|
||||
case Format_d: // int
|
||||
if (t->ty != Tint32 && t->ty != Tuns32)
|
||||
errorPrintfFormat(NULL, slice, e, fmt == Format_u ? "uint" : "int", t);
|
||||
break;
|
||||
|
||||
case Format_hhu: // unsigned char
|
||||
case Format_hhd: // signed char
|
||||
if (t->ty != Tint32 && t->ty != Tuns32 && t->ty != Tint8 && t->ty != Tuns8)
|
||||
errorPrintfFormat(NULL, slice, e, fmt == Format_hhu ? "ubyte" : "byte", t);
|
||||
break;
|
||||
|
||||
case Format_hu: // unsigned short int
|
||||
case Format_hd: // short int
|
||||
if (t->ty != Tint32 && t->ty != Tuns32 && t->ty != Tint16 && t->ty != Tuns16)
|
||||
errorPrintfFormat(NULL, slice, e, fmt == Format_hu ? "ushort" : "short", t);
|
||||
break;
|
||||
|
||||
case Format_lu: // unsigned long int
|
||||
case Format_ld: // long int
|
||||
if (!(t->isintegral() && t->size() == c_longsize))
|
||||
{
|
||||
if (fmt == Format_lu)
|
||||
errorPrintfFormat(NULL, slice, e, (c_longsize == 4 ? "uint" : "ulong"), t);
|
||||
else
|
||||
errorPrintfFormat(NULL, slice, e, (c_longsize == 4 ? "int" : "long"), t);
|
||||
}
|
||||
break;
|
||||
|
||||
case Format_llu: // unsigned long long int
|
||||
case Format_lld: // long long int
|
||||
if (t->ty != Tint64 && t->ty != Tuns64)
|
||||
errorPrintfFormat(NULL, slice, e, fmt == Format_llu ? "ulong" : "long", t);
|
||||
break;
|
||||
|
||||
case Format_ju: // uintmax_t
|
||||
case Format_jd: // intmax_t
|
||||
if (t->ty != Tint64 && t->ty != Tuns64)
|
||||
{
|
||||
if (fmt == Format_ju)
|
||||
errorPrintfFormat(NULL, slice, e, "core.stdc.stdint.uintmax_t", t);
|
||||
else
|
||||
errorPrintfFormat(NULL, slice, e, "core.stdc.stdint.intmax_t", t);
|
||||
}
|
||||
break;
|
||||
|
||||
case Format_zd: // size_t
|
||||
if (!(t->isintegral() && t->size() == ptrsize))
|
||||
errorPrintfFormat(NULL, slice, e, "size_t", t);
|
||||
break;
|
||||
|
||||
case Format_td: // ptrdiff_t
|
||||
if (!(t->isintegral() && t->size() == ptrsize))
|
||||
errorPrintfFormat(NULL, slice, e, "ptrdiff_t", t);
|
||||
break;
|
||||
|
||||
case Format_GNU_a: // Format_GNU_a is only for scanf
|
||||
case Format_lg:
|
||||
case Format_g: // double
|
||||
if (t->ty != Tfloat64 && t->ty != Timaginary64)
|
||||
errorPrintfFormat(NULL, slice, e, "double", t);
|
||||
break;
|
||||
|
||||
case Format_Lg: // long double
|
||||
if (t->ty != Tfloat80 && t->ty != Timaginary80)
|
||||
errorPrintfFormat(NULL, slice, e, "real", t);
|
||||
break;
|
||||
|
||||
case Format_p: // pointer
|
||||
if (t->ty != Tpointer && t->ty != Tnull && t->ty != Tclass && t->ty != Tdelegate && t->ty != Taarray)
|
||||
errorPrintfFormat(NULL, slice, e, "void*", t);
|
||||
break;
|
||||
|
||||
case Format_n: // pointer to int
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tint32))
|
||||
errorPrintfFormat(NULL, slice, e, "int*", t);
|
||||
break;
|
||||
|
||||
case Format_ln: // pointer to long int
|
||||
if (!(t->ty == Tpointer && tnext->isintegral() && !tnext->isunsigned() && tnext->size() == c_longsize))
|
||||
errorPrintfFormat(NULL, slice, e, (c_longsize == 4 ? "int*" : "long*"), t);
|
||||
break;
|
||||
|
||||
case Format_lln: // pointer to long long int
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tint64))
|
||||
errorPrintfFormat(NULL, slice, e, "long*", t);
|
||||
break;
|
||||
|
||||
case Format_hn: // pointer to short
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tint16))
|
||||
errorPrintfFormat(NULL, slice, e, "short*", t);
|
||||
break;
|
||||
|
||||
case Format_hhn: // pointer to signed char
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tint16))
|
||||
errorPrintfFormat(NULL, slice, e, "byte*", t);
|
||||
break;
|
||||
|
||||
case Format_jn: // pointer to intmax_t
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tint64))
|
||||
errorPrintfFormat(NULL, slice, e, "core.stdc.stdint.intmax_t*", t);
|
||||
break;
|
||||
|
||||
case Format_zn: // pointer to size_t
|
||||
if (!(t->ty == Tpointer && tnext->isintegral() && tnext->isunsigned() && tnext->size() == ptrsize))
|
||||
errorPrintfFormat(NULL, slice, e, "size_t*", t);
|
||||
break;
|
||||
|
||||
case Format_tn: // pointer to ptrdiff_t
|
||||
if (!(t->ty == Tpointer && tnext->isintegral() && !tnext->isunsigned() && tnext->size() == ptrsize))
|
||||
errorPrintfFormat(NULL, slice, e, "ptrdiff_t*", t);
|
||||
break;
|
||||
|
||||
case Format_c: // char
|
||||
if (t->ty != Tint32 && t->ty != Tuns32)
|
||||
errorPrintfFormat(NULL, slice, e, "char", t);
|
||||
break;
|
||||
|
||||
case Format_lc: // wint_t
|
||||
if (t->ty != Tint32 && t->ty != Tuns32)
|
||||
errorPrintfFormat(NULL, slice, e, "wchar_t", t);
|
||||
break;
|
||||
|
||||
case Format_s: // pointer to char string
|
||||
if (!(t->ty == Tpointer && (tnext->ty == Tchar || tnext->ty == Tint8 || tnext->ty == Tuns8)))
|
||||
errorPrintfFormat(NULL, slice, e, "char*", t);
|
||||
break;
|
||||
|
||||
case Format_ls: // pointer to wchar_t string
|
||||
{
|
||||
if (!(t->ty == Tpointer && tnext == target.c.twchar_t))
|
||||
errorPrintfFormat(NULL, slice, e, "wchar_t*", t);
|
||||
break;
|
||||
}
|
||||
case Format_error:
|
||||
deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
|
||||
break;
|
||||
|
||||
case Format_GNU_m:
|
||||
break; // not assert(0) because it may go through it if there are extra arguments
|
||||
|
||||
case Format_percent:
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*******************************************/
|
||||
|
||||
static Expression *getNextScanfArg(const Loc &loc, Expressions &args, size_t &n, bool asterisk)
|
||||
{
|
||||
if (n == args.length)
|
||||
{
|
||||
if (!asterisk)
|
||||
deprecation(loc, "more format specifiers than %d arguments", (int)n);
|
||||
return NULL;
|
||||
}
|
||||
return args[n++];
|
||||
}
|
||||
|
||||
static void errorScanfFormat(const char *prefix, DString &slice,
|
||||
Expression *arg, const char *texpect, Type *tactual)
|
||||
{
|
||||
deprecation(arg->loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`",
|
||||
prefix ? prefix : "", arg->toChars(), (int)slice.length, slice.ptr, texpect, tactual->toChars());
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Check that arguments to a scanf format string are compatible
|
||||
* with that string. Issue errors for incompatibilities.
|
||||
*
|
||||
* Follows the C99 specification for scanf.
|
||||
*
|
||||
* Takes a generous, rather than strict, view of compatiblity.
|
||||
* For example, an unsigned value can be formatted with a signed specifier.
|
||||
*
|
||||
* Diagnosed incompatibilities are:
|
||||
*
|
||||
* 1. incompatible sizes which will cause argument misalignment
|
||||
* 2. deferencing arguments that are not pointers
|
||||
* 3. insufficient number of arguments
|
||||
* 4. struct arguments
|
||||
* 5. array and slice arguments
|
||||
* 6. non-standard formats
|
||||
* 7. undefined behavior per C99
|
||||
*
|
||||
* Per the C Standard, extra arguments are ignored.
|
||||
*
|
||||
* No attempt is made to fix the arguments or the format string.
|
||||
*
|
||||
* Params:
|
||||
* loc = location for error messages
|
||||
* format = format string
|
||||
* args = arguments to match with format string
|
||||
* isVa_list = if a "v" function (format check only)
|
||||
*
|
||||
* Returns:
|
||||
* `true` if errors occurred
|
||||
* References:
|
||||
* C99 7.19.6.2
|
||||
* http://www.cplusplus.com/reference/cstdio/scanf/
|
||||
*/
|
||||
bool checkScanfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list)
|
||||
{
|
||||
size_t n = 0;
|
||||
const size_t format_length = strlen(format);
|
||||
for (size_t i = 0; i < format_length;)
|
||||
{
|
||||
if (format[i] != '%')
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
bool asterisk = false;
|
||||
size_t j = i;
|
||||
const Format fmt = parseScanfFormatSpecifier(format, j, asterisk);
|
||||
DString slice = DString(j - i, format + i);
|
||||
i = j;
|
||||
|
||||
if (fmt == Format_percent || asterisk)
|
||||
continue; // "%%", "%*": no arguments
|
||||
|
||||
if (isVa_list)
|
||||
{
|
||||
// format check only
|
||||
if (fmt == Format_error)
|
||||
deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
Expression *e = getNextScanfArg(loc, args, n, asterisk);
|
||||
if (!e)
|
||||
return true;
|
||||
|
||||
Type *t = e->type->toBasetype();
|
||||
Type *tnext = t->nextOf();
|
||||
const unsigned c_longsize = target.c.longsize;
|
||||
const unsigned ptrsize = target.ptrsize;
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case Format_n:
|
||||
case Format_d: // pointer to int
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tint32))
|
||||
errorScanfFormat(NULL, slice, e, "int*", t);
|
||||
break;
|
||||
|
||||
case Format_hhn:
|
||||
case Format_hhd: // pointer to signed char
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tint16))
|
||||
errorScanfFormat(NULL, slice, e, "byte*", t);
|
||||
break;
|
||||
|
||||
case Format_hn:
|
||||
case Format_hd: // pointer to short
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tint16))
|
||||
errorScanfFormat(NULL, slice, e, "short*", t);
|
||||
break;
|
||||
|
||||
case Format_ln:
|
||||
case Format_ld: // pointer to long int
|
||||
if (!(t->ty == Tpointer && tnext->isintegral() && tnext->size() == c_longsize))
|
||||
errorScanfFormat(NULL, slice, e, (c_longsize == 4 ? "int*" : "long*"), t);
|
||||
break;
|
||||
|
||||
case Format_lln:
|
||||
case Format_lld: // pointer to long long int
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tint64))
|
||||
errorScanfFormat(NULL, slice, e, "long*", t);
|
||||
break;
|
||||
|
||||
case Format_jn:
|
||||
case Format_jd: // pointer to intmax_t
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tint64))
|
||||
errorScanfFormat(NULL, slice, e, "core.stdc.stdint.intmax_t*", t);
|
||||
break;
|
||||
|
||||
case Format_zn:
|
||||
case Format_zd: // pointer to size_t
|
||||
if (!(t->ty == Tpointer && tnext->isintegral() && tnext->isunsigned() && tnext->size() == ptrsize))
|
||||
errorScanfFormat(NULL, slice, e, "size_t*", t);
|
||||
break;
|
||||
|
||||
case Format_tn:
|
||||
case Format_td: // pointer to ptrdiff_t
|
||||
if (!(t->ty == Tpointer && tnext->isintegral() && !tnext->isunsigned() && tnext->size() == ptrsize))
|
||||
errorScanfFormat(NULL, slice, e, "ptrdiff_t*", t);
|
||||
break;
|
||||
|
||||
case Format_u: // pointer to unsigned int
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tuns32))
|
||||
errorScanfFormat(NULL, slice, e, "uint*", t);
|
||||
break;
|
||||
|
||||
case Format_hhu: // pointer to unsigned char
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tuns8))
|
||||
errorScanfFormat(NULL, slice, e, "ubyte*", t);
|
||||
break;
|
||||
|
||||
case Format_hu: // pointer to unsigned short int
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tuns16))
|
||||
errorScanfFormat(NULL, slice, e, "ushort*", t);
|
||||
break;
|
||||
|
||||
case Format_lu: // pointer to unsigned long int
|
||||
if (!(t->ty == Tpointer && tnext->isintegral() && tnext->isunsigned() && tnext->size() == c_longsize))
|
||||
errorScanfFormat(NULL, slice, e, (c_longsize == 4 ? "uint*" : "ulong*"), t);
|
||||
break;
|
||||
|
||||
case Format_llu: // pointer to unsigned long long int
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tuns64))
|
||||
errorScanfFormat(NULL, slice, e, "ulong*", t);
|
||||
break;
|
||||
|
||||
case Format_ju: // pointer to uintmax_t
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tuns64))
|
||||
errorScanfFormat(NULL, slice, e, "ulong*", t);
|
||||
break;
|
||||
|
||||
case Format_g: // pointer to float
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tfloat32))
|
||||
errorScanfFormat(NULL, slice, e, "float*", t);
|
||||
break;
|
||||
|
||||
case Format_lg: // pointer to double
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tfloat64))
|
||||
errorScanfFormat(NULL, slice, e, "double*", t);
|
||||
break;
|
||||
|
||||
case Format_Lg: // pointer to long double
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tfloat80))
|
||||
errorScanfFormat(NULL, slice, e, "real*", t);
|
||||
break;
|
||||
|
||||
case Format_GNU_a:
|
||||
case Format_GNU_m:
|
||||
case Format_c:
|
||||
case Format_s: // pointer to char string
|
||||
if (!(t->ty == Tpointer && (tnext->ty == Tchar || tnext->ty == Tint8 || tnext->ty == Tuns8)))
|
||||
errorScanfFormat(NULL, slice, e, "char*", t);
|
||||
break;
|
||||
|
||||
case Format_lc:
|
||||
case Format_ls: // pointer to wchar_t string
|
||||
{
|
||||
if (!(t->ty == Tpointer && tnext == target.c.twchar_t))
|
||||
errorScanfFormat(NULL, slice, e, "wchar_t*", t);
|
||||
break;
|
||||
}
|
||||
case Format_p: // double pointer
|
||||
if (!(t->ty == Tpointer && tnext->ty == Tpointer))
|
||||
errorScanfFormat(NULL, slice, e, "void**", t);
|
||||
break;
|
||||
|
||||
case Format_error:
|
||||
deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
|
||||
break;
|
||||
|
||||
case Format_percent:
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
1364
gcc/d/dmd/chkformat.d
Normal file
1364
gcc/d/dmd/chkformat.d
Normal file
File diff suppressed because it is too large
Load diff
1179
gcc/d/dmd/clone.c
1179
gcc/d/dmd/clone.c
File diff suppressed because it is too large
Load diff
1695
gcc/d/dmd/clone.d
Normal file
1695
gcc/d/dmd/clone.d
Normal file
File diff suppressed because it is too large
Load diff
57
gcc/d/dmd/compiler.d
Normal file
57
gcc/d/dmd/compiler.d
Normal file
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Describes a back-end compiler and implements compiler-specific actions.
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/compiler.d, _compiler.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_compiler.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/compiler.d
|
||||
*/
|
||||
|
||||
module dmd.compiler;
|
||||
|
||||
import dmd.arraytypes;
|
||||
import dmd.dmodule;
|
||||
import dmd.dscope;
|
||||
import dmd.expression;
|
||||
import dmd.mtype;
|
||||
import dmd.root.array;
|
||||
|
||||
extern (C++) __gshared
|
||||
{
|
||||
bool includeImports = false;
|
||||
// array of module patterns used to include/exclude imported modules
|
||||
Array!(const(char)*) includeModulePatterns;
|
||||
Modules compiledImports;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A data structure that describes a back-end compiler and implements
|
||||
* compiler-specific actions.
|
||||
*/
|
||||
extern (C++) struct Compiler
|
||||
{
|
||||
/******************************
|
||||
* Encode the given expression, which is assumed to be an rvalue literal
|
||||
* as another type for use in CTFE.
|
||||
* This corresponds roughly to the idiom *(Type *)&e.
|
||||
*/
|
||||
extern (C++) static Expression paintAsType(UnionExp* pue, Expression e, Type type);
|
||||
|
||||
/******************************
|
||||
* For the given module, perform any post parsing analysis.
|
||||
* Certain compiler backends (ie: GDC) have special placeholder
|
||||
* modules whose source are empty, but code gets injected
|
||||
* immediately after loading.
|
||||
*/
|
||||
extern (C++) static void onParseModule(Module m);
|
||||
|
||||
/**
|
||||
* A callback function that is called once an imported module is
|
||||
* parsed. If the callback returns true, then it tells the
|
||||
* frontend that the driver intends on compiling the import.
|
||||
*/
|
||||
extern (C++) static bool onImport(Module m);
|
||||
}
|
|
@ -22,11 +22,6 @@ class Type;
|
|||
struct Scope;
|
||||
struct UnionExp;
|
||||
|
||||
// DMD-generated module `__entrypoint` where the C main resides
|
||||
extern Module *entrypoint;
|
||||
// Module in which the D main is
|
||||
extern Module *rootHasMain;
|
||||
|
||||
extern bool includeImports;
|
||||
// array of module patterns used to include/exclude imported modules
|
||||
extern Array<const char*> includeModulePatterns;
|
||||
|
@ -37,7 +32,6 @@ struct Compiler
|
|||
// CTFE support for cross-compilation.
|
||||
static Expression *paintAsType(UnionExp *, Expression *, Type *);
|
||||
// Backend
|
||||
static void genCmain(Scope *);
|
||||
static bool onImport(Module *);
|
||||
static void onParseModule(Module *);
|
||||
};
|
||||
|
|
112
gcc/d/dmd/complex.d
Normal file
112
gcc/d/dmd/complex.d
Normal file
|
@ -0,0 +1,112 @@
|
|||
/**
|
||||
* Implements a complex number type.
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/complex.d, _complex.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_complex.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/complex.d
|
||||
*/
|
||||
|
||||
module dmd.complex;
|
||||
|
||||
import dmd.root.ctfloat;
|
||||
|
||||
extern (C++) struct complex_t
|
||||
{
|
||||
real_t re;
|
||||
real_t im;
|
||||
|
||||
this() @disable;
|
||||
|
||||
this(real_t re)
|
||||
{
|
||||
this(re, CTFloat.zero);
|
||||
}
|
||||
|
||||
this(real_t re, real_t im)
|
||||
{
|
||||
this.re = re;
|
||||
this.im = im;
|
||||
}
|
||||
|
||||
extern (D) complex_t opBinary(string op)(complex_t y)
|
||||
if (op == "+")
|
||||
{
|
||||
return complex_t(re + y.re, im + y.im);
|
||||
}
|
||||
|
||||
extern (D) complex_t opBinary(string op)(complex_t y)
|
||||
if (op == "-")
|
||||
{
|
||||
return complex_t(re - y.re, im - y.im);
|
||||
}
|
||||
|
||||
extern (D) complex_t opUnary(string op)()
|
||||
if (op == "-")
|
||||
{
|
||||
return complex_t(-re, -im);
|
||||
}
|
||||
|
||||
extern (D) complex_t opBinary(string op)(complex_t y)
|
||||
if (op == "*")
|
||||
{
|
||||
return complex_t(re * y.re - im * y.im, im * y.re + re * y.im);
|
||||
}
|
||||
|
||||
extern (D) complex_t opBinaryRight(string op)(real_t x)
|
||||
if (op == "*")
|
||||
{
|
||||
return complex_t(x) * this;
|
||||
}
|
||||
|
||||
extern (D) complex_t opBinary(string op)(real_t y)
|
||||
if (op == "*")
|
||||
{
|
||||
return this * complex_t(y);
|
||||
}
|
||||
|
||||
extern (D) complex_t opBinary(string op)(real_t y)
|
||||
if (op == "/")
|
||||
{
|
||||
return this / complex_t(y);
|
||||
}
|
||||
|
||||
extern (D) complex_t opBinary(string op)(complex_t y)
|
||||
if (op == "/")
|
||||
{
|
||||
if (CTFloat.fabs(y.re) < CTFloat.fabs(y.im))
|
||||
{
|
||||
const r = y.re / y.im;
|
||||
const den = y.im + r * y.re;
|
||||
return complex_t((re * r + im) / den, (im * r - re) / den);
|
||||
}
|
||||
else
|
||||
{
|
||||
const r = y.im / y.re;
|
||||
const den = y.re + r * y.im;
|
||||
return complex_t((re + r * im) / den, (im - r * re) / den);
|
||||
}
|
||||
}
|
||||
|
||||
extern (D) bool opCast(T : bool)() const
|
||||
{
|
||||
return re || im;
|
||||
}
|
||||
|
||||
int opEquals(complex_t y) const
|
||||
{
|
||||
return re == y.re && im == y.im;
|
||||
}
|
||||
}
|
||||
|
||||
extern (C++) real_t creall(complex_t x)
|
||||
{
|
||||
return x.re;
|
||||
}
|
||||
|
||||
extern (C++) real_t cimagl(complex_t x)
|
||||
{
|
||||
return x.im;
|
||||
}
|
|
@ -20,7 +20,7 @@ struct complex_t
|
|||
real_t re;
|
||||
real_t im;
|
||||
|
||||
complex_t(real_t re) : re(re), im(ldouble(0)) {}
|
||||
complex_t(real_t re) : re(re), im(CTFloat::zero) {}
|
||||
complex_t(real_t re, real_t im) : re(re), im(im) {}
|
||||
|
||||
complex_t operator + (complex_t y) { return complex_t(re + y.re, im + y.im); }
|
||||
|
@ -52,7 +52,7 @@ struct complex_t
|
|||
int operator != (complex_t y) { return re != y.re || im != y.im; }
|
||||
|
||||
private:
|
||||
complex_t() : re(ldouble(0)), im(ldouble(0)) {}
|
||||
complex_t() : re(CTFloat::zero), im(CTFloat::zero) {}
|
||||
};
|
||||
|
||||
inline complex_t operator * (real_t x, complex_t y) { return complex_t(x) * y; }
|
||||
|
|
738
gcc/d/dmd/cond.c
738
gcc/d/dmd/cond.c
|
@ -1,738 +0,0 @@
|
|||
|
||||
/* Compiler implementation of the D programming language
|
||||
* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/D-Programming-Language/dmd/blob/master/src/cond.c
|
||||
*/
|
||||
|
||||
#include "root/dsystem.h" // strcmp()
|
||||
|
||||
#include "mars.h"
|
||||
#include "id.h"
|
||||
#include "init.h"
|
||||
#include "aggregate.h"
|
||||
#include "declaration.h"
|
||||
#include "identifier.h"
|
||||
#include "expression.h"
|
||||
#include "cond.h"
|
||||
#include "module.h"
|
||||
#include "template.h"
|
||||
#include "mtype.h"
|
||||
#include "scope.h"
|
||||
#include "statement.h"
|
||||
#include "arraytypes.h"
|
||||
#include "tokens.h"
|
||||
|
||||
bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
|
||||
|
||||
int findCondition(Identifiers *ids, Identifier *ident)
|
||||
{
|
||||
if (ids)
|
||||
{
|
||||
for (size_t i = 0; i < ids->length; i++)
|
||||
{
|
||||
Identifier *id = (*ids)[i];
|
||||
|
||||
if (id == ident)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
|
||||
Condition::Condition(Loc loc)
|
||||
{
|
||||
this->loc = loc;
|
||||
inc = 0;
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
|
||||
StaticForeach::StaticForeach(Loc loc, ForeachStatement *aggrfe, ForeachRangeStatement *rangefe)
|
||||
{
|
||||
assert(!!aggrfe ^ !!rangefe);
|
||||
this->loc = loc;
|
||||
this->aggrfe = aggrfe;
|
||||
this->rangefe = rangefe;
|
||||
this->needExpansion = false;
|
||||
}
|
||||
|
||||
StaticForeach *StaticForeach::syntaxCopy()
|
||||
{
|
||||
return new StaticForeach(
|
||||
loc,
|
||||
aggrfe ? (ForeachStatement *)aggrfe->syntaxCopy() : NULL,
|
||||
rangefe ? (ForeachRangeStatement *)rangefe->syntaxCopy() : NULL
|
||||
);
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Turn an aggregate which is an array into an expression tuple
|
||||
* of its elements. I.e., lower
|
||||
* static foreach (x; [1, 2, 3, 4]) { ... }
|
||||
* to
|
||||
* static foreach (x; AliasSeq!(1, 2, 3, 4)) { ... }
|
||||
*/
|
||||
|
||||
static void lowerArrayAggregate(StaticForeach *sfe, Scope *sc)
|
||||
{
|
||||
Expression *aggr = sfe->aggrfe->aggr;
|
||||
Expression *el = new ArrayLengthExp(aggr->loc, aggr);
|
||||
sc = sc->startCTFE();
|
||||
el = expressionSemantic(el, sc);
|
||||
sc = sc->endCTFE();
|
||||
el = el->optimize(WANTvalue);
|
||||
el = el->ctfeInterpret();
|
||||
if (el->op == TOKint64)
|
||||
{
|
||||
Expressions *es;
|
||||
if (ArrayLiteralExp *ale = aggr->isArrayLiteralExp())
|
||||
{
|
||||
// Directly use the elements of the array for the TupleExp creation
|
||||
es = ale->elements;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t length = (size_t)el->toInteger();
|
||||
es = new Expressions();
|
||||
es->setDim(length);
|
||||
for (size_t i = 0; i < length; i++)
|
||||
{
|
||||
IntegerExp *index = new IntegerExp(sfe->loc, i, Type::tsize_t);
|
||||
Expression *value = new IndexExp(aggr->loc, aggr, index);
|
||||
(*es)[i] = value;
|
||||
}
|
||||
}
|
||||
sfe->aggrfe->aggr = new TupleExp(aggr->loc, es);
|
||||
sfe->aggrfe->aggr = expressionSemantic(sfe->aggrfe->aggr, sc);
|
||||
sfe->aggrfe->aggr = sfe->aggrfe->aggr->optimize(WANTvalue);
|
||||
sfe->aggrfe->aggr = sfe->aggrfe->aggr->ctfeInterpret();
|
||||
}
|
||||
else
|
||||
{
|
||||
sfe->aggrfe->aggr = new ErrorExp();
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Wrap a statement into a function literal and call it.
|
||||
*
|
||||
* Params:
|
||||
* loc = The source location.
|
||||
* s = The statement.
|
||||
* Returns:
|
||||
* AST of the expression `(){ s; }()` with location loc.
|
||||
*/
|
||||
|
||||
static Expression *wrapAndCall(Loc loc, Statement *s)
|
||||
{
|
||||
TypeFunction *tf = new TypeFunction(ParameterList(), NULL, LINKdefault, 0);
|
||||
FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, loc, tf, TOKreserved, NULL);
|
||||
fd->fbody = s;
|
||||
FuncExp *fe = new FuncExp(loc, fd);
|
||||
Expression *ce = new CallExp(loc, fe, new Expressions());
|
||||
return ce;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Create a `foreach` statement from `aggrefe/rangefe` with given
|
||||
* `foreach` variables and body `s`.
|
||||
*
|
||||
* Params:
|
||||
* loc = The source location.
|
||||
* parameters = The foreach variables.
|
||||
* s = The `foreach` body.
|
||||
* Returns:
|
||||
* `foreach (parameters; aggregate) s;` or
|
||||
* `foreach (parameters; lower .. upper) s;`
|
||||
* Where aggregate/lower, upper are as for the current StaticForeach.
|
||||
*/
|
||||
|
||||
static Statement *createForeach(StaticForeach *sfe, Loc loc, Parameters *parameters, Statement *s)
|
||||
{
|
||||
if (sfe->aggrfe)
|
||||
{
|
||||
return new ForeachStatement(loc, sfe->aggrfe->op, parameters, sfe->aggrfe->aggr->syntaxCopy(), s, loc);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(sfe->rangefe && parameters->length == 1);
|
||||
return new ForeachRangeStatement(loc, sfe->rangefe->op, (*parameters)[0],
|
||||
sfe->rangefe->lwr->syntaxCopy(),
|
||||
sfe->rangefe->upr->syntaxCopy(), s, loc);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* For a `static foreach` with multiple loop variables, the
|
||||
* aggregate is lowered to an array of tuples. As D does not have
|
||||
* built-in tuples, we need a suitable tuple type. This generates
|
||||
* a `struct` that serves as the tuple type. This type is only
|
||||
* used during CTFE and hence its typeinfo will not go to the
|
||||
* object file.
|
||||
*
|
||||
* Params:
|
||||
* loc = The source location.
|
||||
* e = The expressions we wish to store in the tuple.
|
||||
* sc = The current scope.
|
||||
* Returns:
|
||||
* A struct type of the form
|
||||
* struct Tuple
|
||||
* {
|
||||
* typeof(AliasSeq!(e)) tuple;
|
||||
* }
|
||||
*/
|
||||
|
||||
static TypeStruct *createTupleType(Loc loc, Expressions *e)
|
||||
{ // TODO: move to druntime?
|
||||
Identifier *sid = Identifier::generateId("Tuple");
|
||||
StructDeclaration *sdecl = new StructDeclaration(loc, sid, false);
|
||||
sdecl->storage_class |= STCstatic;
|
||||
sdecl->members = new Dsymbols();
|
||||
Identifier *fid = Identifier::idPool("tuple");
|
||||
Type *ty = new TypeTypeof(loc, new TupleExp(loc, e));
|
||||
sdecl->members->push(new VarDeclaration(loc, ty, fid, NULL));
|
||||
TypeStruct *r = (TypeStruct *)sdecl->type;
|
||||
if (global.params.useTypeInfo && Type::dtypeinfo)
|
||||
r->vtinfo = TypeInfoStructDeclaration::create(r); // prevent typeinfo from going to object file
|
||||
return r;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Create the AST for an instantiation of a suitable tuple type.
|
||||
*
|
||||
* Params:
|
||||
* loc = The source location.
|
||||
* type = A Tuple type, created with createTupleType.
|
||||
* e = The expressions we wish to store in the tuple.
|
||||
* Returns:
|
||||
* An AST for the expression `Tuple(e)`.
|
||||
*/
|
||||
|
||||
static Expression *createTuple(Loc loc, TypeStruct *type, Expressions *e)
|
||||
{ // TODO: move to druntime?
|
||||
return new CallExp(loc, new TypeExp(loc, type), e);
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Lower any aggregate that is not an array to an array using a
|
||||
* regular foreach loop within CTFE. If there are multiple
|
||||
* `static foreach` loop variables, an array of tuples is
|
||||
* generated. In thise case, the field `needExpansion` is set to
|
||||
* true to indicate that the static foreach loop expansion will
|
||||
* need to expand the tuples into multiple variables.
|
||||
*
|
||||
* For example, `static foreach (x; range) { ... }` is lowered to:
|
||||
*
|
||||
* static foreach (x; {
|
||||
* typeof({
|
||||
* foreach (x; range) return x;
|
||||
* }())[] __res;
|
||||
* foreach (x; range) __res ~= x;
|
||||
* return __res;
|
||||
* }()) { ... }
|
||||
*
|
||||
* Finally, call `lowerArrayAggregate` to turn the produced
|
||||
* array into an expression tuple.
|
||||
*
|
||||
* Params:
|
||||
* sc = The current scope.
|
||||
*/
|
||||
|
||||
static void lowerNonArrayAggregate(StaticForeach *sfe, Scope *sc)
|
||||
{
|
||||
size_t nvars = sfe->aggrfe ? sfe->aggrfe->parameters->length : 1;
|
||||
Loc aloc = sfe->aggrfe ? sfe->aggrfe->aggr->loc : sfe->rangefe->lwr->loc;
|
||||
// We need three sets of foreach loop variables because the
|
||||
// lowering contains three foreach loops.
|
||||
Parameters *pparams[3] = {new Parameters(), new Parameters(), new Parameters()};
|
||||
for (size_t i = 0; i < nvars; i++)
|
||||
{
|
||||
for (size_t j = 0; j < 3; j++)
|
||||
{
|
||||
Parameters *params = pparams[j];
|
||||
Parameter *p = sfe->aggrfe ? (*sfe->aggrfe->parameters)[i] : sfe->rangefe->prm;
|
||||
params->push(new Parameter(p->storageClass, p->type, p->ident, NULL, NULL));
|
||||
}
|
||||
}
|
||||
Expression *res[2];
|
||||
TypeStruct *tplty = NULL;
|
||||
if (nvars == 1) // only one `static foreach` variable, generate identifiers.
|
||||
{
|
||||
for (size_t i = 0; i < 2; i++)
|
||||
{
|
||||
res[i] = new IdentifierExp(aloc, (*pparams[i])[0]->ident);
|
||||
}
|
||||
}
|
||||
else // multiple `static foreach` variables, generate tuples.
|
||||
{
|
||||
for (size_t i = 0; i < 2; i++)
|
||||
{
|
||||
Expressions *e = new Expressions();
|
||||
for (size_t j = 0; j < pparams[0]->length; j++)
|
||||
{
|
||||
Parameter *p = (*pparams[i])[j];
|
||||
e->push(new IdentifierExp(aloc, p->ident));
|
||||
}
|
||||
if (!tplty)
|
||||
{
|
||||
tplty = createTupleType(aloc, e);
|
||||
}
|
||||
res[i] = createTuple(aloc, tplty, e);
|
||||
}
|
||||
sfe->needExpansion = true; // need to expand the tuples later
|
||||
}
|
||||
// generate remaining code for the new aggregate which is an
|
||||
// array (see documentation comment).
|
||||
if (sfe->rangefe)
|
||||
{
|
||||
sc = sc->startCTFE();
|
||||
sfe->rangefe->lwr = expressionSemantic(sfe->rangefe->lwr, sc);
|
||||
sfe->rangefe->lwr = resolveProperties(sc, sfe->rangefe->lwr);
|
||||
sfe->rangefe->upr = expressionSemantic(sfe->rangefe->upr, sc);
|
||||
sfe->rangefe->upr = resolveProperties(sc, sfe->rangefe->upr);
|
||||
sc = sc->endCTFE();
|
||||
sfe->rangefe->lwr = sfe->rangefe->lwr->optimize(WANTvalue);
|
||||
sfe->rangefe->lwr = sfe->rangefe->lwr->ctfeInterpret();
|
||||
sfe->rangefe->upr = sfe->rangefe->upr->optimize(WANTvalue);
|
||||
sfe->rangefe->upr = sfe->rangefe->upr->ctfeInterpret();
|
||||
}
|
||||
Statements *s1 = new Statements();
|
||||
Statements *sfebody = new Statements();
|
||||
if (tplty) sfebody->push(new ExpStatement(sfe->loc, tplty->sym));
|
||||
sfebody->push(new ReturnStatement(aloc, res[0]));
|
||||
s1->push(createForeach(sfe, aloc, pparams[0], new CompoundStatement(aloc, sfebody)));
|
||||
s1->push(new ExpStatement(aloc, new AssertExp(aloc, new IntegerExp(aloc, 0, Type::tint32))));
|
||||
Type *ety = new TypeTypeof(aloc, wrapAndCall(aloc, new CompoundStatement(aloc, s1)));
|
||||
Type *aty = ety->arrayOf();
|
||||
Identifier *idres = Identifier::generateId("__res");
|
||||
VarDeclaration *vard = new VarDeclaration(aloc, aty, idres, NULL);
|
||||
Statements *s2 = new Statements();
|
||||
|
||||
// Run 'typeof' gagged to avoid duplicate errors and if it fails just create
|
||||
// an empty foreach to expose them.
|
||||
unsigned olderrors = global.startGagging();
|
||||
ety = typeSemantic(ety, aloc, sc);
|
||||
if (global.endGagging(olderrors))
|
||||
s2->push(createForeach(sfe, aloc, pparams[1], NULL));
|
||||
else
|
||||
{
|
||||
s2->push(new ExpStatement(aloc, vard));
|
||||
Expression *catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]);
|
||||
s2->push(createForeach(sfe, aloc, pparams[1], new ExpStatement(aloc, catass)));
|
||||
s2->push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres)));
|
||||
}
|
||||
|
||||
Expression *aggr;
|
||||
Type *indexty;
|
||||
|
||||
if (sfe->rangefe && (indexty = ety)->isintegral())
|
||||
{
|
||||
sfe->rangefe->lwr->type = indexty;
|
||||
sfe->rangefe->upr->type = indexty;
|
||||
IntRange lwrRange = getIntRange(sfe->rangefe->lwr);
|
||||
IntRange uprRange = getIntRange(sfe->rangefe->upr);
|
||||
|
||||
const dinteger_t lwr = sfe->rangefe->lwr->toInteger();
|
||||
dinteger_t upr = sfe->rangefe->upr->toInteger();
|
||||
size_t length = 0;
|
||||
|
||||
if (lwrRange.imin <= uprRange.imax)
|
||||
length = (size_t)(upr - lwr);
|
||||
|
||||
Expressions *exps = new Expressions();
|
||||
exps->setDim(length);
|
||||
|
||||
if (sfe->rangefe->op == TOKforeach)
|
||||
{
|
||||
for (size_t i = 0; i < length; i++)
|
||||
(*exps)[i] = new IntegerExp(aloc, lwr + i, indexty);
|
||||
}
|
||||
else
|
||||
{
|
||||
--upr;
|
||||
for (size_t i = 0; i < length; i++)
|
||||
(*exps)[i] = new IntegerExp(aloc, upr - i, indexty);
|
||||
}
|
||||
aggr = new ArrayLiteralExp(aloc, indexty->arrayOf(), exps);
|
||||
}
|
||||
else
|
||||
{
|
||||
aggr = wrapAndCall(aloc, new CompoundStatement(aloc, s2));
|
||||
sc = sc->startCTFE();
|
||||
aggr = expressionSemantic(aggr, sc);
|
||||
aggr = resolveProperties(sc, aggr);
|
||||
sc = sc->endCTFE();
|
||||
aggr = aggr->optimize(WANTvalue);
|
||||
aggr = aggr->ctfeInterpret();
|
||||
}
|
||||
|
||||
assert(!!sfe->aggrfe ^ !!sfe->rangefe);
|
||||
sfe->aggrfe = new ForeachStatement(sfe->loc, TOKforeach, pparams[2], aggr,
|
||||
sfe->aggrfe ? sfe->aggrfe->_body : sfe->rangefe->_body,
|
||||
sfe->aggrfe ? sfe->aggrfe->endloc : sfe->rangefe->endloc);
|
||||
sfe->rangefe = NULL;
|
||||
lowerArrayAggregate(sfe, sc); // finally, turn generated array into expression tuple
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Perform `static foreach` lowerings that are necessary in order
|
||||
* to finally expand the `static foreach` using
|
||||
* `ddmd.statementsem.makeTupleForeach`.
|
||||
*/
|
||||
|
||||
void staticForeachPrepare(StaticForeach *sfe, Scope *sc)
|
||||
{
|
||||
assert(sc);
|
||||
if (sfe->aggrfe)
|
||||
{
|
||||
sc = sc->startCTFE();
|
||||
sfe->aggrfe->aggr = expressionSemantic(sfe->aggrfe->aggr, sc);
|
||||
sc = sc->endCTFE();
|
||||
sfe->aggrfe->aggr = sfe->aggrfe->aggr->optimize(WANTvalue);
|
||||
}
|
||||
|
||||
if (sfe->aggrfe && sfe->aggrfe->aggr->type->toBasetype()->ty == Terror)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!staticForeachReady(sfe))
|
||||
{
|
||||
if (sfe->aggrfe && sfe->aggrfe->aggr->type->toBasetype()->ty == Tarray)
|
||||
{
|
||||
lowerArrayAggregate(sfe, sc);
|
||||
}
|
||||
else
|
||||
{
|
||||
lowerNonArrayAggregate(sfe, sc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Returns:
|
||||
* `true` iff ready to call `ddmd.statementsem.makeTupleForeach`.
|
||||
*/
|
||||
|
||||
bool staticForeachReady(StaticForeach *sfe)
|
||||
{
|
||||
return sfe->aggrfe && sfe->aggrfe->aggr && sfe->aggrfe->aggr->type &&
|
||||
sfe->aggrfe->aggr->type->toBasetype()->ty == Ttuple;
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
|
||||
DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident)
|
||||
: Condition(Loc())
|
||||
{
|
||||
this->mod = mod;
|
||||
this->level = level;
|
||||
this->ident = ident;
|
||||
}
|
||||
|
||||
Condition *DVCondition::syntaxCopy()
|
||||
{
|
||||
return this; // don't need to copy
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
|
||||
void DebugCondition::addGlobalIdent(const char *ident)
|
||||
{
|
||||
if (!global.debugids)
|
||||
global.debugids = new Identifiers();
|
||||
global.debugids->push(Identifier::idPool(ident));
|
||||
}
|
||||
|
||||
|
||||
DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident)
|
||||
: DVCondition(mod, level, ident)
|
||||
{
|
||||
}
|
||||
|
||||
// Helper for printing dependency information
|
||||
void printDepsConditional(Scope *sc, DVCondition* condition, const char* depType)
|
||||
{
|
||||
if (!global.params.moduleDeps || global.params.moduleDepsFile.length)
|
||||
return;
|
||||
OutBuffer *ob = global.params.moduleDeps;
|
||||
Module* imod = sc ? sc->instantiatingModule() : condition->mod;
|
||||
if (!imod)
|
||||
return;
|
||||
ob->writestring(depType);
|
||||
ob->writestring(imod->toPrettyChars());
|
||||
ob->writestring(" (");
|
||||
escapePath(ob, imod->srcfile->toChars());
|
||||
ob->writestring(") : ");
|
||||
if (condition->ident)
|
||||
ob->printf("%s\n", condition->ident->toChars());
|
||||
else
|
||||
ob->printf("%d\n", condition->level);
|
||||
}
|
||||
|
||||
|
||||
int DebugCondition::include(Scope *sc)
|
||||
{
|
||||
//printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
|
||||
if (inc == 0)
|
||||
{
|
||||
inc = 2;
|
||||
bool definedInModule = false;
|
||||
if (ident)
|
||||
{
|
||||
if (findCondition(mod->debugids, ident))
|
||||
{
|
||||
inc = 1;
|
||||
definedInModule = true;
|
||||
}
|
||||
else if (findCondition(global.debugids, ident))
|
||||
inc = 1;
|
||||
else
|
||||
{ if (!mod->debugidsNot)
|
||||
mod->debugidsNot = new Identifiers();
|
||||
mod->debugidsNot->push(ident);
|
||||
}
|
||||
}
|
||||
else if (level <= global.params.debuglevel || level <= mod->debuglevel)
|
||||
inc = 1;
|
||||
if (!definedInModule)
|
||||
printDepsConditional(sc, this, "depsDebug ");
|
||||
}
|
||||
return (inc == 1);
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
|
||||
static bool isReserved(const char *ident)
|
||||
{
|
||||
static const char* reserved[] =
|
||||
{
|
||||
"DigitalMars",
|
||||
"GNU",
|
||||
"LDC",
|
||||
"SDC",
|
||||
"Windows",
|
||||
"Win32",
|
||||
"Win64",
|
||||
"linux",
|
||||
"OSX",
|
||||
"FreeBSD",
|
||||
"OpenBSD",
|
||||
"NetBSD",
|
||||
"DragonFlyBSD",
|
||||
"BSD",
|
||||
"Solaris",
|
||||
"Posix",
|
||||
"AIX",
|
||||
"Haiku",
|
||||
"SkyOS",
|
||||
"SysV3",
|
||||
"SysV4",
|
||||
"Hurd",
|
||||
"Android",
|
||||
"PlayStation",
|
||||
"PlayStation4",
|
||||
"Cygwin",
|
||||
"MinGW",
|
||||
"FreeStanding",
|
||||
"X86",
|
||||
"X86_64",
|
||||
"ARM",
|
||||
"ARM_Thumb",
|
||||
"ARM_SoftFloat",
|
||||
"ARM_SoftFP",
|
||||
"ARM_HardFloat",
|
||||
"AArch64",
|
||||
"Epiphany",
|
||||
"PPC",
|
||||
"PPC_SoftFloat",
|
||||
"PPC_HardFloat",
|
||||
"PPC64",
|
||||
"IA64",
|
||||
"MIPS32",
|
||||
"MIPS64",
|
||||
"MIPS_O32",
|
||||
"MIPS_N32",
|
||||
"MIPS_O64",
|
||||
"MIPS_N64",
|
||||
"MIPS_EABI",
|
||||
"MIPS_SoftFloat",
|
||||
"MIPS_HardFloat",
|
||||
"MSP430",
|
||||
"NVPTX",
|
||||
"NVPTX64",
|
||||
"RISCV32",
|
||||
"RISCV64",
|
||||
"SPARC",
|
||||
"SPARC_V8Plus",
|
||||
"SPARC_SoftFloat",
|
||||
"SPARC_HardFloat",
|
||||
"SPARC64",
|
||||
"S390",
|
||||
"S390X",
|
||||
"HPPA",
|
||||
"HPPA64",
|
||||
"SH",
|
||||
"Alpha",
|
||||
"Alpha_SoftFloat",
|
||||
"Alpha_HardFloat",
|
||||
"LittleEndian",
|
||||
"BigEndian",
|
||||
"ELFv1",
|
||||
"ELFv2",
|
||||
"CRuntime_Digitalmars",
|
||||
"CRuntime_Glibc",
|
||||
"CRuntime_Microsoft",
|
||||
"CRuntime_Musl",
|
||||
"CRuntime_UClibc",
|
||||
"CppRuntime_Clang",
|
||||
"CppRuntime_DigitalMars",
|
||||
"CppRuntime_Gcc",
|
||||
"CppRuntime_Microsoft",
|
||||
"CppRuntime_Sun",
|
||||
"D_Coverage",
|
||||
"D_Ddoc",
|
||||
"D_InlineAsm_X86",
|
||||
"D_InlineAsm_X86_64",
|
||||
"D_LP64",
|
||||
"D_X32",
|
||||
"D_HardFloat",
|
||||
"D_SoftFloat",
|
||||
"D_PIC",
|
||||
"D_SIMD",
|
||||
"D_Version2",
|
||||
"D_NoBoundsChecks",
|
||||
"unittest",
|
||||
"assert",
|
||||
"all",
|
||||
"none",
|
||||
NULL
|
||||
};
|
||||
|
||||
for (unsigned i = 0; reserved[i]; i++)
|
||||
{
|
||||
if (strcmp(ident, reserved[i]) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ident[0] == 'D' && ident[1] == '_')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void checkReserved(Loc loc, const char *ident)
|
||||
{
|
||||
if (isReserved(ident))
|
||||
error(loc, "version identifier `%s` is reserved and cannot be set", ident);
|
||||
}
|
||||
|
||||
void VersionCondition::addGlobalIdent(const char *ident)
|
||||
{
|
||||
checkReserved(Loc(), ident);
|
||||
addPredefinedGlobalIdent(ident);
|
||||
}
|
||||
|
||||
void VersionCondition::addPredefinedGlobalIdent(const char *ident)
|
||||
{
|
||||
if (!global.versionids)
|
||||
global.versionids = new Identifiers();
|
||||
global.versionids->push(Identifier::idPool(ident));
|
||||
}
|
||||
|
||||
|
||||
VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
|
||||
: DVCondition(mod, level, ident)
|
||||
{
|
||||
}
|
||||
|
||||
int VersionCondition::include(Scope *sc)
|
||||
{
|
||||
//printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
|
||||
//if (ident) printf("\tident = '%s'\n", ident->toChars());
|
||||
if (inc == 0)
|
||||
{
|
||||
inc = 2;
|
||||
bool definedInModule=false;
|
||||
if (ident)
|
||||
{
|
||||
if (findCondition(mod->versionids, ident))
|
||||
{
|
||||
inc = 1;
|
||||
definedInModule = true;
|
||||
}
|
||||
else if (findCondition(global.versionids, ident))
|
||||
inc = 1;
|
||||
else
|
||||
{
|
||||
if (!mod->versionidsNot)
|
||||
mod->versionidsNot = new Identifiers();
|
||||
mod->versionidsNot->push(ident);
|
||||
}
|
||||
}
|
||||
else if (level <= global.params.versionlevel || level <= mod->versionlevel)
|
||||
inc = 1;
|
||||
if (!definedInModule && (!ident || (!isReserved(ident->toChars()) && ident != Id::_unittest && ident != Id::_assert)))
|
||||
printDepsConditional(sc, this, "depsVersion ");
|
||||
}
|
||||
return (inc == 1);
|
||||
}
|
||||
|
||||
/**************************** StaticIfCondition *******************************/
|
||||
|
||||
StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
|
||||
: Condition(loc)
|
||||
{
|
||||
this->exp = exp;
|
||||
}
|
||||
|
||||
Condition *StaticIfCondition::syntaxCopy()
|
||||
{
|
||||
return new StaticIfCondition(loc, exp->syntaxCopy());
|
||||
}
|
||||
|
||||
int StaticIfCondition::include(Scope *sc)
|
||||
{
|
||||
if (inc == 0)
|
||||
{
|
||||
if (!sc)
|
||||
{
|
||||
error(loc, "static if conditional cannot be at global scope");
|
||||
inc = 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sc = sc->push(sc->scopesym);
|
||||
|
||||
bool errors = false;
|
||||
|
||||
if (!exp)
|
||||
goto Lerror;
|
||||
|
||||
bool result = evalStaticCondition(sc, exp, exp, errors);
|
||||
sc->pop();
|
||||
|
||||
// Prevent repeated condition evaluation.
|
||||
// See: fail_compilation/fail7815.d
|
||||
if (inc != 0)
|
||||
return (inc == 1);
|
||||
if (errors)
|
||||
goto Lerror;
|
||||
if (result)
|
||||
inc = 1;
|
||||
else
|
||||
inc = 2;
|
||||
}
|
||||
return (inc == 1);
|
||||
|
||||
Lerror:
|
||||
if (!global.gag)
|
||||
inc = 2; // so we don't see the error message again
|
||||
return 0;
|
||||
}
|
1004
gcc/d/dmd/cond.d
Normal file
1004
gcc/d/dmd/cond.d
Normal file
File diff suppressed because it is too large
Load diff
|
@ -16,26 +16,24 @@
|
|||
|
||||
class Expression;
|
||||
class Identifier;
|
||||
struct OutBuffer;
|
||||
class Module;
|
||||
struct Scope;
|
||||
class ScopeDsymbol;
|
||||
class DebugCondition;
|
||||
class ForeachStatement;
|
||||
class ForeachRangeStatement;
|
||||
|
||||
int findCondition(Identifiers *ids, Identifier *ident);
|
||||
enum Include
|
||||
{
|
||||
INCLUDEnotComputed, /// not computed yet
|
||||
INCLUDEyes, /// include the conditional code
|
||||
INCLUDEno /// do not include the conditional code
|
||||
};
|
||||
|
||||
class Condition : public ASTNode
|
||||
{
|
||||
public:
|
||||
Loc loc;
|
||||
// 0: not computed yet
|
||||
// 1: include
|
||||
// 2: do not include
|
||||
int inc;
|
||||
|
||||
Condition(Loc loc);
|
||||
Include inc;
|
||||
|
||||
virtual Condition *syntaxCopy() = 0;
|
||||
virtual int include(Scope *sc) = 0;
|
||||
|
@ -54,13 +52,9 @@ public:
|
|||
|
||||
bool needExpansion;
|
||||
|
||||
StaticForeach(Loc loc, ForeachStatement *aggrfe, ForeachRangeStatement *rangefe);
|
||||
StaticForeach *syntaxCopy();
|
||||
};
|
||||
|
||||
void staticForeachPrepare(StaticForeach *sfe, Scope *sc);
|
||||
bool staticForeachReady(StaticForeach *sfe);
|
||||
|
||||
class DVCondition : public Condition
|
||||
{
|
||||
public:
|
||||
|
@ -68,9 +62,7 @@ public:
|
|||
Identifier *ident;
|
||||
Module *mod;
|
||||
|
||||
DVCondition(Module *mod, unsigned level, Identifier *ident);
|
||||
|
||||
Condition *syntaxCopy();
|
||||
DVCondition *syntaxCopy();
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
|
@ -79,8 +71,6 @@ class DebugCondition : public DVCondition
|
|||
public:
|
||||
static void addGlobalIdent(const char *ident);
|
||||
|
||||
DebugCondition(Module *mod, unsigned level, Identifier *ident);
|
||||
|
||||
int include(Scope *sc);
|
||||
DebugCondition *isDebugCondition() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -92,8 +82,6 @@ public:
|
|||
static void addGlobalIdent(const char *ident);
|
||||
static void addPredefinedGlobalIdent(const char *ident);
|
||||
|
||||
VersionCondition(Module *mod, unsigned level, Identifier *ident);
|
||||
|
||||
int include(Scope *sc);
|
||||
VersionCondition *isVersionCondition() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -104,8 +92,7 @@ class StaticIfCondition : public Condition
|
|||
public:
|
||||
Expression *exp;
|
||||
|
||||
StaticIfCondition(Loc loc, Expression *exp);
|
||||
Condition *syntaxCopy();
|
||||
StaticIfCondition *syntaxCopy();
|
||||
int include(Scope *sc);
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load diff
1825
gcc/d/dmd/constfold.d
Normal file
1825
gcc/d/dmd/constfold.d
Normal file
File diff suppressed because it is too large
Load diff
4249
gcc/d/dmd/cparse.d
Normal file
4249
gcc/d/dmd/cparse.d
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
2540
gcc/d/dmd/cppmangle.d
Normal file
2540
gcc/d/dmd/cppmangle.d
Normal file
File diff suppressed because it is too large
Load diff
222
gcc/d/dmd/ctfe.h
222
gcc/d/dmd/ctfe.h
|
@ -5,30 +5,14 @@
|
|||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/dlang/dmd/blob/master/src/ctfe.h
|
||||
* https://github.com/dlang/dmd/blob/master/src/dmd/ctfe.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arraytypes.h"
|
||||
#include "tokens.h"
|
||||
#include "expression.h"
|
||||
|
||||
/**
|
||||
Global status of the CTFE engine. Mostly used for performance diagnostics
|
||||
*/
|
||||
struct CtfeStatus
|
||||
{
|
||||
static int callDepth; // current number of recursive calls
|
||||
/* When printing a stack trace,
|
||||
* suppress this number of calls
|
||||
*/
|
||||
static int stackTraceCallsToSuppress;
|
||||
static int maxCallDepth; // highest number of recursive calls
|
||||
static int numArrayAllocs; // Number of allocated arrays
|
||||
static int numAssignments; // total number of assignments executed
|
||||
};
|
||||
|
||||
/**
|
||||
A reference to a class, or an interface. We need this when we
|
||||
point to a base class (we must record what the type is).
|
||||
|
@ -37,55 +21,35 @@ class ClassReferenceExp : public Expression
|
|||
{
|
||||
public:
|
||||
StructLiteralExp *value;
|
||||
ClassReferenceExp(Loc loc, StructLiteralExp *lit, Type *type);
|
||||
ClassDeclaration *originalClass();
|
||||
|
||||
/// Return index of the field, or -1 if not found
|
||||
int getFieldIndex(Type *fieldtype, unsigned fieldoffset);
|
||||
/// Return index of the field, or -1 if not found
|
||||
/// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
|
||||
int findFieldIndexByName(VarDeclaration *v);
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
// The various functions are used only to detect compiler CTFE bugs
|
||||
Expression *getValue(VarDeclaration *vd);
|
||||
bool hasValue(VarDeclaration *vd);
|
||||
void setValueNull(VarDeclaration *vd);
|
||||
void setValueWithoutChecking(VarDeclaration *vd, Expression *newval);
|
||||
void setValue(VarDeclaration *vd, Expression *newval);
|
||||
|
||||
/// Return index of the field, or -1 if not found
|
||||
/// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
|
||||
int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v);
|
||||
|
||||
|
||||
/** An uninitialized value
|
||||
/**
|
||||
An uninitialized value
|
||||
*/
|
||||
class VoidInitExp : public Expression
|
||||
{
|
||||
public:
|
||||
VarDeclaration *var;
|
||||
|
||||
VoidInitExp(VarDeclaration *var, Type *type);
|
||||
const char *toChars();
|
||||
const char *toChars() const;
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
// Create an appropriate void initializer
|
||||
UnionExp voidInitLiteral(Type *t, VarDeclaration *var);
|
||||
|
||||
/** Fake class which holds the thrown exception.
|
||||
Used for implementing exception handling.
|
||||
/**
|
||||
Fake class which holds the thrown exception.
|
||||
Used for implementing exception handling.
|
||||
*/
|
||||
class ThrownExceptionExp : public Expression
|
||||
{
|
||||
public:
|
||||
ClassReferenceExp *thrown; // the thing being tossed
|
||||
ThrownExceptionExp(Loc loc, ClassReferenceExp *victim);
|
||||
const char *toChars();
|
||||
/// Generate an error message when this exception is not caught
|
||||
void generateUncaughtError();
|
||||
const char *toChars() const;
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
|
@ -96,173 +60,5 @@ public:
|
|||
class CTFEExp : public Expression
|
||||
{
|
||||
public:
|
||||
CTFEExp(TOK tok);
|
||||
|
||||
const char *toChars();
|
||||
|
||||
// Handy instances to share
|
||||
static CTFEExp *cantexp;
|
||||
static CTFEExp *voidexp;
|
||||
static CTFEExp *breakexp;
|
||||
static CTFEExp *continueexp;
|
||||
static CTFEExp *gotoexp;
|
||||
|
||||
static bool isCantExp(Expression *e) { return e && e->op == TOKcantexp; }
|
||||
static bool isGotoExp(Expression *e) { return e && e->op == TOKgoto; }
|
||||
const char *toChars() const;
|
||||
};
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
/// True if 'e' is TOKcantexp, or an exception
|
||||
bool exceptionOrCantInterpret(Expression *e);
|
||||
|
||||
// Used for debugging only
|
||||
void showCtfeExpr(Expression *e, int level = 0);
|
||||
|
||||
/// Return true if this is a valid CTFE expression
|
||||
bool isCtfeValueValid(Expression *newval);
|
||||
bool isCtfeReferenceValid(Expression *newval);
|
||||
|
||||
/// Given expr, which evaluates to an array/AA/string literal,
|
||||
/// return true if it needs to be copied
|
||||
bool needToCopyLiteral(Expression *expr);
|
||||
|
||||
/// Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral.
|
||||
/// This value will be used for in-place modification.
|
||||
UnionExp copyLiteral(Expression *e);
|
||||
|
||||
/// Set this literal to the given type, copying it if necessary
|
||||
Expression *paintTypeOntoLiteral(Type *type, Expression *lit);
|
||||
Expression *paintTypeOntoLiteral(UnionExp *pue, Type *type, Expression *lit);
|
||||
UnionExp paintTypeOntoLiteralCopy(Type *type, Expression *lit);
|
||||
|
||||
/// Convert from a CTFE-internal slice, into a normal Expression
|
||||
Expression *resolveSlice(Expression *e, UnionExp *pue = NULL);
|
||||
|
||||
/// Determine the array length, without interpreting the expression.
|
||||
uinteger_t resolveArrayLength(Expression *e);
|
||||
|
||||
/// Create an array literal consisting of 'elem' duplicated 'dim' times.
|
||||
ArrayLiteralExp *createBlockDuplicatedArrayLiteral(UnionExp *pue, Loc loc, Type *type,
|
||||
Expression *elem, size_t dim);
|
||||
|
||||
/// Create a string literal consisting of 'value' duplicated 'dim' times.
|
||||
StringExp *createBlockDuplicatedStringLiteral(UnionExp *pue, Loc loc, Type *type,
|
||||
unsigned value, size_t dim, unsigned char sz);
|
||||
|
||||
|
||||
/* Set dest = src, where both dest and src are container value literals
|
||||
* (ie, struct literals, or static arrays (can be an array literal or a string)
|
||||
* Assignment is recursively in-place.
|
||||
* Purpose: any reference to a member of 'dest' will remain valid after the
|
||||
* assignment.
|
||||
*/
|
||||
void assignInPlace(Expression *dest, Expression *src);
|
||||
|
||||
/// Duplicate the elements array, then set field 'indexToChange' = newelem.
|
||||
Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expression *newelem);
|
||||
|
||||
/// Given an AA literal aae, set arr[index] = newval and return the new array.
|
||||
Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae,
|
||||
Expression *index, Expression *newval);
|
||||
|
||||
/// Given array literal oldval of type ArrayLiteralExp or StringExp, of length
|
||||
/// oldlen, change its length to newlen. If the newlen is longer than oldlen,
|
||||
/// all new elements will be set to the default initializer for the element type.
|
||||
UnionExp changeArrayLiteralLength(Loc loc, TypeArray *arrayType,
|
||||
Expression *oldval, size_t oldlen, size_t newlen);
|
||||
|
||||
|
||||
|
||||
/// Return true if t is a pointer (not a function pointer)
|
||||
bool isPointer(Type *t);
|
||||
|
||||
// For CTFE only. Returns true if 'e' is TRUE or a non-null pointer.
|
||||
bool isTrueBool(Expression *e);
|
||||
|
||||
/// Is it safe to convert from srcPointee* to destPointee* ?
|
||||
/// srcPointee is the genuine type (never void).
|
||||
/// destPointee may be void.
|
||||
bool isSafePointerCast(Type *srcPointee, Type *destPointee);
|
||||
|
||||
/// Given pointer e, return the memory block expression it points to,
|
||||
/// and set ofs to the offset within that memory block.
|
||||
Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs);
|
||||
|
||||
/// Return true if agg1 and agg2 are pointers to the same memory block
|
||||
bool pointToSameMemoryBlock(Expression *agg1, Expression *agg2);
|
||||
|
||||
// return e1 - e2 as an integer, or error if not possible
|
||||
UnionExp pointerDifference(Loc loc, Type *type, Expression *e1, Expression *e2);
|
||||
|
||||
/// Return 1 if true, 0 if false
|
||||
/// -1 if comparison is illegal because they point to non-comparable memory blocks
|
||||
int comparePointers(TOK op, Expression *agg1, dinteger_t ofs1, Expression *agg2, dinteger_t ofs2);
|
||||
|
||||
// Return eptr op e2, where eptr is a pointer, e2 is an integer,
|
||||
// and op is TOKadd or TOKmin
|
||||
UnionExp pointerArithmetic(Loc loc, TOK op, Type *type,
|
||||
Expression *eptr, Expression *e2);
|
||||
|
||||
// True if conversion from type 'from' to 'to' involves a reinterpret_cast
|
||||
// floating point -> integer or integer -> floating point
|
||||
bool isFloatIntPaint(Type *to, Type *from);
|
||||
|
||||
// Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
|
||||
Expression *paintFloatInt(UnionExp *pue, Expression *fromVal, Type *to);
|
||||
|
||||
/// Return true if t is an AA
|
||||
bool isAssocArray(Type *t);
|
||||
|
||||
/// Given a template AA type, extract the corresponding built-in AA type
|
||||
TypeAArray *toBuiltinAAType(Type *t);
|
||||
|
||||
/* Given an AA literal 'ae', and a key 'e2':
|
||||
* Return ae[e2] if present, or NULL if not found.
|
||||
* Return TOKcantexp on error.
|
||||
*/
|
||||
Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2);
|
||||
|
||||
/// True if type is TypeInfo_Class
|
||||
bool isTypeInfo_Class(Type *type);
|
||||
|
||||
|
||||
/***********************************************
|
||||
COW const-folding operations
|
||||
***********************************************/
|
||||
|
||||
/// Return true if non-pointer expression e can be compared
|
||||
/// with >,is, ==, etc, using ctfeCmp, ctfeEquals, ctfeIdentity
|
||||
bool isCtfeComparable(Expression *e);
|
||||
|
||||
/// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1
|
||||
int ctfeEqual(Loc loc, TOK op, Expression *e1, Expression *e2);
|
||||
|
||||
/// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1
|
||||
int ctfeIdentity(Loc loc, TOK op, Expression *e1, Expression *e2);
|
||||
|
||||
/// Returns rawCmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
|
||||
int specificCmp(TOK op, int rawCmp);
|
||||
|
||||
/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
|
||||
int intUnsignedCmp(TOK op, dinteger_t n1, dinteger_t n2);
|
||||
|
||||
/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
|
||||
int intSignedCmp(TOK op, sinteger_t n1, sinteger_t n2);
|
||||
|
||||
/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
|
||||
int realCmp(TOK op, real_t r1, real_t r2);
|
||||
|
||||
/// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
|
||||
int ctfeCmp(Loc loc, TOK op, Expression *e1, Expression *e2);
|
||||
|
||||
/// Returns e1 ~ e2. Resolves slices before concatenation.
|
||||
UnionExp ctfeCat(Loc loc, Type *type, Expression *e1, Expression *e2);
|
||||
|
||||
/// Same as for constfold.Index, except that it only works for static arrays,
|
||||
/// dynamic arrays, and strings.
|
||||
Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx);
|
||||
|
||||
/// Cast 'e' of type 'type' to type 'to'.
|
||||
Expression *ctfeCast(UnionExp *pue, Loc loc, Type *type, Type *to, Expression *e);
|
||||
|
|
2127
gcc/d/dmd/ctfeexpr.c
2127
gcc/d/dmd/ctfeexpr.c
File diff suppressed because it is too large
Load diff
2096
gcc/d/dmd/ctfeexpr.d
Normal file
2096
gcc/d/dmd/ctfeexpr.d
Normal file
File diff suppressed because it is too large
Load diff
225
gcc/d/dmd/ctorflow.d
Normal file
225
gcc/d/dmd/ctorflow.d
Normal file
|
@ -0,0 +1,225 @@
|
|||
/**
|
||||
* Manage flow analysis for constructors.
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctorflow.d, _ctorflow.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_ctorflow.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ctorflow.d
|
||||
*/
|
||||
|
||||
module dmd.ctorflow;
|
||||
|
||||
import core.stdc.stdio;
|
||||
|
||||
import dmd.root.rmem;
|
||||
import dmd.globals : Loc;
|
||||
|
||||
enum CSX : ushort
|
||||
{
|
||||
none = 0,
|
||||
this_ctor = 0x01, /// called this()
|
||||
super_ctor = 0x02, /// called super()
|
||||
label = 0x04, /// seen a label
|
||||
return_ = 0x08, /// seen a return statement
|
||||
any_ctor = 0x10, /// either this() or super() was called
|
||||
halt = 0x20, /// assert(0)
|
||||
}
|
||||
|
||||
/// Individual field in the Ctor with information about its callees and location.
|
||||
struct FieldInit
|
||||
{
|
||||
CSX csx; /// information about the field's callees
|
||||
Loc loc; /// location of the field initialization
|
||||
}
|
||||
|
||||
/***********
|
||||
* Primitive flow analysis for constructors
|
||||
*/
|
||||
struct CtorFlow
|
||||
{
|
||||
CSX callSuper; /// state of calling other constructors
|
||||
|
||||
FieldInit[] fieldinit; /// state of field initializations
|
||||
|
||||
void allocFieldinit(size_t dim)
|
||||
{
|
||||
fieldinit = (cast(FieldInit*)mem.xcalloc(FieldInit.sizeof, dim))[0 .. dim];
|
||||
}
|
||||
|
||||
void freeFieldinit()
|
||||
{
|
||||
if (fieldinit.ptr)
|
||||
mem.xfree(fieldinit.ptr);
|
||||
|
||||
fieldinit = null;
|
||||
}
|
||||
|
||||
/***********************
|
||||
* Create a deep copy of `this`
|
||||
* Returns:
|
||||
* a copy
|
||||
*/
|
||||
CtorFlow clone()
|
||||
{
|
||||
return CtorFlow(callSuper, fieldinit.arraydup);
|
||||
}
|
||||
|
||||
/**********************************
|
||||
* Set CSX bits in flow analysis state
|
||||
* Params:
|
||||
* csx = bits to set
|
||||
*/
|
||||
void orCSX(CSX csx) nothrow pure
|
||||
{
|
||||
callSuper |= csx;
|
||||
foreach (ref u; fieldinit)
|
||||
u.csx |= csx;
|
||||
}
|
||||
|
||||
/******************************
|
||||
* OR CSX bits to `this`
|
||||
* Params:
|
||||
* ctorflow = bits to OR in
|
||||
*/
|
||||
void OR(const ref CtorFlow ctorflow) pure nothrow
|
||||
{
|
||||
callSuper |= ctorflow.callSuper;
|
||||
if (fieldinit.length && ctorflow.fieldinit.length)
|
||||
{
|
||||
assert(fieldinit.length == ctorflow.fieldinit.length);
|
||||
foreach (i, u; ctorflow.fieldinit)
|
||||
{
|
||||
auto fi = &fieldinit[i];
|
||||
fi.csx |= u.csx;
|
||||
if (fi.loc is Loc.init)
|
||||
fi.loc = u.loc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************************
|
||||
* Merge `b` flow analysis results into `a`.
|
||||
* Params:
|
||||
* a = the path to merge `b` into
|
||||
* b = the other path
|
||||
* Returns:
|
||||
* false means one of the paths skips construction
|
||||
*/
|
||||
bool mergeCallSuper(ref CSX a, const CSX b) pure nothrow
|
||||
{
|
||||
// This does a primitive flow analysis to support the restrictions
|
||||
// regarding when and how constructors can appear.
|
||||
// It merges the results of two paths.
|
||||
// The two paths are `a` and `b`; the result is merged into `a`.
|
||||
if (b == a)
|
||||
return true;
|
||||
|
||||
// Have ALL branches called a constructor?
|
||||
const aAll = (a & (CSX.this_ctor | CSX.super_ctor)) != 0;
|
||||
const bAll = (b & (CSX.this_ctor | CSX.super_ctor)) != 0;
|
||||
// Have ANY branches called a constructor?
|
||||
const aAny = (a & CSX.any_ctor) != 0;
|
||||
const bAny = (b & CSX.any_ctor) != 0;
|
||||
// Have any branches returned?
|
||||
const aRet = (a & CSX.return_) != 0;
|
||||
const bRet = (b & CSX.return_) != 0;
|
||||
// Have any branches halted?
|
||||
const aHalt = (a & CSX.halt) != 0;
|
||||
const bHalt = (b & CSX.halt) != 0;
|
||||
if (aHalt && bHalt)
|
||||
{
|
||||
a = CSX.halt;
|
||||
}
|
||||
else if ((!bHalt && bRet && !bAny && aAny) || (!aHalt && aRet && !aAny && bAny))
|
||||
{
|
||||
// If one has returned without a constructor call, there must not
|
||||
// be ctor calls in the other.
|
||||
return false;
|
||||
}
|
||||
else if (bHalt || bRet && bAll)
|
||||
{
|
||||
// If one branch has called a ctor and then exited, anything the
|
||||
// other branch has done is OK (except returning without a
|
||||
// ctor call, but we already checked that).
|
||||
a |= b & (CSX.any_ctor | CSX.label);
|
||||
}
|
||||
else if (aHalt || aRet && aAll)
|
||||
{
|
||||
a = cast(CSX)(b | (a & (CSX.any_ctor | CSX.label)));
|
||||
}
|
||||
else if (aAll != bAll) // both branches must have called ctors, or both not
|
||||
return false;
|
||||
else
|
||||
{
|
||||
// If one returned without a ctor, remember that
|
||||
if (bRet && !bAny)
|
||||
a |= CSX.return_;
|
||||
a |= b & (CSX.any_ctor | CSX.label);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/****************************************
|
||||
* Merge `b` flow analysis results into `a`.
|
||||
* Params:
|
||||
* a = the path to merge `b` into
|
||||
* b = the other path
|
||||
* Returns:
|
||||
* false means either `a` or `b` skips initialization
|
||||
*/
|
||||
bool mergeFieldInit(ref CSX a, const CSX b) pure nothrow
|
||||
{
|
||||
if (b == a)
|
||||
return true;
|
||||
|
||||
// Have any branches returned?
|
||||
const aRet = (a & CSX.return_) != 0;
|
||||
const bRet = (b & CSX.return_) != 0;
|
||||
// Have any branches halted?
|
||||
const aHalt = (a & CSX.halt) != 0;
|
||||
const bHalt = (b & CSX.halt) != 0;
|
||||
|
||||
if (aHalt && bHalt)
|
||||
{
|
||||
a = CSX.halt;
|
||||
return true;
|
||||
}
|
||||
|
||||
// The logic here is to prefer the branch that neither halts nor returns.
|
||||
bool ok;
|
||||
if (!bHalt && bRet)
|
||||
{
|
||||
// Branch b returns, no merging required.
|
||||
ok = (b & CSX.this_ctor);
|
||||
}
|
||||
else if (!aHalt && aRet)
|
||||
{
|
||||
// Branch a returns, but b doesn't, b takes precedence.
|
||||
ok = (a & CSX.this_ctor);
|
||||
a = b;
|
||||
}
|
||||
else if (bHalt)
|
||||
{
|
||||
// Branch b halts, no merging required.
|
||||
ok = (a & CSX.this_ctor);
|
||||
}
|
||||
else if (aHalt)
|
||||
{
|
||||
// Branch a halts, but b doesn't, b takes precedence.
|
||||
ok = (b & CSX.this_ctor);
|
||||
a = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Neither branch returns nor halts, merge flags.
|
||||
ok = !((a ^ b) & CSX.this_ctor);
|
||||
a |= b;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
3566
gcc/d/dmd/dcast.c
3566
gcc/d/dmd/dcast.c
File diff suppressed because it is too large
Load diff
3741
gcc/d/dmd/dcast.d
Normal file
3741
gcc/d/dmd/dcast.d
Normal file
File diff suppressed because it is too large
Load diff
1041
gcc/d/dmd/dclass.c
1041
gcc/d/dmd/dclass.c
File diff suppressed because it is too large
Load diff
1139
gcc/d/dmd/dclass.d
Normal file
1139
gcc/d/dmd/dclass.d
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
2323
gcc/d/dmd/declaration.d
Normal file
2323
gcc/d/dmd/declaration.d
Normal file
File diff suppressed because it is too large
Load diff
|
@ -13,115 +13,98 @@
|
|||
#include "dsymbol.h"
|
||||
#include "mtype.h"
|
||||
#include "objc.h"
|
||||
#include "tokens.h"
|
||||
|
||||
class Expression;
|
||||
class Statement;
|
||||
class LabelDsymbol;
|
||||
class Initializer;
|
||||
class Module;
|
||||
class ForeachStatement;
|
||||
struct Ensure
|
||||
{
|
||||
Identifier *id;
|
||||
Statement *ensure;
|
||||
|
||||
Ensure();
|
||||
Ensure(Identifier *id, Statement *ensure);
|
||||
Ensure syntaxCopy();
|
||||
static Ensures *arraySyntaxCopy(Ensures *a);
|
||||
};
|
||||
class AliasDeclaration;
|
||||
class FuncDeclaration;
|
||||
class ExpInitializer;
|
||||
class StructDeclaration;
|
||||
struct InterState;
|
||||
struct CompiledCtfeFunction;
|
||||
struct ObjcSelector;
|
||||
struct IntRange;
|
||||
|
||||
enum LINK;
|
||||
enum TOK;
|
||||
enum MATCH;
|
||||
enum PURE;
|
||||
enum PINLINE;
|
||||
//enum STC : ulong from astenums.d:
|
||||
|
||||
#define STCundefined 0ULL
|
||||
|
||||
#define STCstatic 1ULL /// `static`
|
||||
#define STCextern 2ULL /// `extern`
|
||||
#define STCconst 4ULL /// `const`
|
||||
#define STCfinal 8ULL /// `final`
|
||||
|
||||
#define STCabstract 0x10ULL /// `abstract`
|
||||
#define STCparameter 0x20ULL /// is function parameter
|
||||
#define STCfield 0x40ULL /// is field of struct, union or class
|
||||
#define STCoverride 0x80ULL /// `override`
|
||||
|
||||
#define STCauto 0x100ULL /// `auto`
|
||||
#define STCsynchronized 0x200ULL /// `synchronized`
|
||||
#define STCdeprecated 0x400ULL /// `deprecated`
|
||||
#define STCin 0x800ULL /// `in` parameter
|
||||
|
||||
#define STCout 0x1000ULL /// `out` parameter
|
||||
#define STClazy 0x2000ULL /// `lazy` parameter
|
||||
#define STCforeach 0x4000ULL /// variable for foreach loop
|
||||
#define STCvariadic 0x8000ULL /// the `variadic` parameter in: T foo(T a, U b, V variadic...)
|
||||
|
||||
#define STCctorinit 0x10000ULL /// can only be set inside constructor
|
||||
#define STCtemplateparameter 0x20000ULL /// template parameter
|
||||
#define STCref 0x40000ULL /// `ref`
|
||||
#define STCscope 0x80000ULL /// `scope`
|
||||
|
||||
#define STCmaybescope 0x100000ULL /// parameter might be `scope`
|
||||
#define STCscopeinferred 0x200000ULL /// `scope` has been inferred and should not be part of mangling, `scope` must also be set
|
||||
#define STCreturn 0x400000ULL /// 'return ref' or 'return scope' for function parameters
|
||||
#define STCreturnScope 0x800000ULL /// if `ref return scope` then resolve to `ref` and `return scope`
|
||||
|
||||
#define STCreturninferred 0x1000000ULL /// `return` has been inferred and should not be part of mangling, `return` must also be set
|
||||
#define STCimmutable 0x2000000ULL /// `immutable`
|
||||
#define STCinit 0x4000000ULL /// has explicit initializer
|
||||
#define STCmanifest 0x8000000ULL /// manifest constant
|
||||
|
||||
#define STCnodtor 0x10000000ULL /// do not run destructor
|
||||
#define STCnothrow 0x20000000ULL /// `nothrow` meaning never throws exceptions
|
||||
#define STCpure 0x40000000ULL /// `pure` function
|
||||
#define STCtls 0x80000000ULL /// thread local
|
||||
|
||||
#define STCalias 0x100000000ULL /// `alias` parameter
|
||||
#define STCshared 0x200000000ULL /// accessible from multiple threads
|
||||
#define STCgshared 0x400000000ULL /// accessible from multiple threads, but not typed as `shared`
|
||||
#define STCwild 0x800000000ULL /// for wild type constructor
|
||||
|
||||
#define STCproperty 0x1000000000ULL /// `@property`
|
||||
#define STCsafe 0x2000000000ULL /// `@safe`
|
||||
#define STCtrusted 0x4000000000ULL /// `@trusted`
|
||||
#define STCsystem 0x8000000000ULL /// `@system`
|
||||
|
||||
#define STCctfe 0x10000000000ULL /// can be used in CTFE, even if it is static
|
||||
#define STCdisable 0x20000000000ULL /// for functions that are not callable
|
||||
#define STCresult 0x40000000000ULL /// for result variables passed to out contracts
|
||||
#define STCnodefaultctor 0x80000000000ULL /// must be set inside constructor
|
||||
|
||||
#define STCtemp 0x100000000000ULL /// temporary variable
|
||||
#define STCrvalue 0x200000000000ULL /// force rvalue for variables
|
||||
#define STCnogc 0x400000000000ULL /// `@nogc`
|
||||
#define STCautoref 0x800000000000ULL /// Mark for the already deduced `auto ref` parameter
|
||||
|
||||
#define STCinference 0x1000000000000ULL /// do attribute inference
|
||||
#define STCexptemp 0x2000000000000ULL /// temporary variable that has lifetime restricted to an expression
|
||||
#define STCfuture 0x4000000000000ULL /// introducing new base class function
|
||||
#define STClocal 0x8000000000000ULL /// do not forward (see dmd.dsymbol.ForwardingScopeDsymbol).
|
||||
|
||||
#define STClive 0x10000000000000ULL /// function `@live` attribute
|
||||
#define STCregister 0x20000000000000ULL /// `register` storage class (ImportC)
|
||||
#define STCvolatile 0x40000000000000ULL /// destined for volatile in the back end
|
||||
|
||||
#define STCundefined 0LL
|
||||
#define STCstatic 1LL
|
||||
#define STCextern 2LL
|
||||
#define STCconst 4LL
|
||||
#define STCfinal 8LL
|
||||
#define STCabstract 0x10LL
|
||||
#define STCparameter 0x20LL
|
||||
#define STCfield 0x40LL
|
||||
#define STCoverride 0x80LL
|
||||
#define STCauto 0x100LL
|
||||
#define STCsynchronized 0x200LL
|
||||
#define STCdeprecated 0x400LL
|
||||
#define STCin 0x800LL // in parameter
|
||||
#define STCout 0x1000LL // out parameter
|
||||
#define STClazy 0x2000LL // lazy parameter
|
||||
#define STCforeach 0x4000LL // variable for foreach loop
|
||||
#define STCvariadic 0x10000LL // the 'variadic' parameter in: T foo(T a, U b, V variadic...)
|
||||
#define STCctorinit 0x20000LL // can only be set inside constructor
|
||||
#define STCtemplateparameter 0x40000LL // template parameter
|
||||
#define STCscope 0x80000LL
|
||||
#define STCimmutable 0x100000LL
|
||||
#define STCref 0x200000LL
|
||||
#define STCinit 0x400000LL // has explicit initializer
|
||||
#define STCmanifest 0x800000LL // manifest constant
|
||||
#define STCnodtor 0x1000000LL // don't run destructor
|
||||
#define STCnothrow 0x2000000LL // never throws exceptions
|
||||
#define STCpure 0x4000000LL // pure function
|
||||
#define STCtls 0x8000000LL // thread local
|
||||
#define STCalias 0x10000000LL // alias parameter
|
||||
#define STCshared 0x20000000LL // accessible from multiple threads
|
||||
// accessible from multiple threads
|
||||
// but not typed as "shared"
|
||||
#define STCgshared 0x40000000LL
|
||||
#define STCwild 0x80000000LL // for "wild" type constructor
|
||||
#define STC_TYPECTOR (STCconst | STCimmutable | STCshared | STCwild)
|
||||
#define STC_FUNCATTR (STCref | STCnothrow | STCnogc | STCpure | STCproperty | STCsafe | STCtrusted | STCsystem)
|
||||
|
||||
#define STCproperty 0x100000000LL
|
||||
#define STCsafe 0x200000000LL
|
||||
#define STCtrusted 0x400000000LL
|
||||
#define STCsystem 0x800000000LL
|
||||
#define STCctfe 0x1000000000LL // can be used in CTFE, even if it is static
|
||||
#define STCdisable 0x2000000000LL // for functions that are not callable
|
||||
#define STCresult 0x4000000000LL // for result variables passed to out contracts
|
||||
#define STCnodefaultctor 0x8000000000LL // must be set inside constructor
|
||||
#define STCtemp 0x10000000000LL // temporary variable
|
||||
#define STCrvalue 0x20000000000LL // force rvalue for variables
|
||||
#define STCnogc 0x40000000000LL // @nogc
|
||||
#define STCvolatile 0x80000000000LL // destined for volatile in the back end
|
||||
#define STCreturn 0x100000000000LL // 'return ref' or 'return scope' for function parameters
|
||||
#define STCautoref 0x200000000000LL // Mark for the already deduced 'auto ref' parameter
|
||||
#define STCinference 0x400000000000LL // do attribute inference
|
||||
#define STCexptemp 0x800000000000LL // temporary variable that has lifetime restricted to an expression
|
||||
#define STCmaybescope 0x1000000000000LL // parameter might be 'scope'
|
||||
#define STCscopeinferred 0x2000000000000LL // 'scope' has been inferred and should not be part of mangling
|
||||
#define STCfuture 0x4000000000000LL // introducing new base class function
|
||||
#define STClocal 0x8000000000000LL // do not forward (see ddmd.dsymbol.ForwardingScopeDsymbol).
|
||||
|
||||
const StorageClass STCStorageClass = (STCauto | STCscope | STCstatic | STCextern | STCconst | STCfinal |
|
||||
STCabstract | STCsynchronized | STCdeprecated | STCfuture | STCoverride | STClazy | STCalias |
|
||||
STCout | STCin |
|
||||
STCmanifest | STCimmutable | STCshared | STCwild | STCnothrow | STCnogc | STCpure | STCref | STCtls |
|
||||
STCgshared | STCproperty | STCsafe | STCtrusted | STCsystem | STCdisable | STClocal);
|
||||
|
||||
struct Match
|
||||
{
|
||||
int count; // number of matches found
|
||||
MATCH last; // match level of lastf
|
||||
FuncDeclaration *lastf; // last matching function we found
|
||||
FuncDeclaration *nextf; // current matching function
|
||||
FuncDeclaration *anyf; // pick a func, any func, to use for error recovery
|
||||
};
|
||||
|
||||
void functionResolve(Match *m, Dsymbol *fd, Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs, const char **pMessage = NULL);
|
||||
int overloadApply(Dsymbol *fstart, void *param, int (*fp)(void *, Dsymbol *));
|
||||
void aliasSemantic(AliasDeclaration *ds, Scope *sc);
|
||||
|
||||
void ObjectNotFound(Identifier *id);
|
||||
|
||||
/**************************************************************/
|
||||
|
@ -132,47 +115,45 @@ public:
|
|||
Type *type;
|
||||
Type *originalType; // before semantic analysis
|
||||
StorageClass storage_class;
|
||||
Prot protection;
|
||||
Visibility visibility;
|
||||
LINK linkage;
|
||||
int inuse; // used to detect cycles
|
||||
short inuse; // used to detect cycles
|
||||
uint8_t adFlags;
|
||||
DString mangleOverride; // overridden symbol with pragma(mangle, "...")
|
||||
|
||||
Declaration(Identifier *id);
|
||||
const char *kind() const;
|
||||
d_uns64 size(Loc loc);
|
||||
bool checkDisabled(Loc loc, Scope *sc, bool isAliasedDeclaration = false);
|
||||
int checkModify(Loc loc, Scope *sc, Type *t, Expression *e1, int flag);
|
||||
d_uns64 size(const Loc &loc);
|
||||
|
||||
Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
|
||||
|
||||
bool isStatic() { return (storage_class & STCstatic) != 0; }
|
||||
bool isStatic() const { return (storage_class & STCstatic) != 0; }
|
||||
virtual bool isDelete();
|
||||
virtual bool isDataseg();
|
||||
virtual bool isThreadlocal();
|
||||
virtual bool isCodeseg() const;
|
||||
bool isCtorinit() { return (storage_class & STCctorinit) != 0; }
|
||||
bool isFinal() { return (storage_class & STCfinal) != 0; }
|
||||
bool isAbstract() { return (storage_class & STCabstract) != 0; }
|
||||
bool isConst() { return (storage_class & STCconst) != 0; }
|
||||
bool isImmutable() { return (storage_class & STCimmutable) != 0; }
|
||||
bool isWild() { return (storage_class & STCwild) != 0; }
|
||||
bool isAuto() { return (storage_class & STCauto) != 0; }
|
||||
bool isScope() { return (storage_class & STCscope) != 0; }
|
||||
bool isSynchronized() { return (storage_class & STCsynchronized) != 0; }
|
||||
bool isParameter() { return (storage_class & STCparameter) != 0; }
|
||||
bool isDeprecated() { return (storage_class & STCdeprecated) != 0; }
|
||||
bool isDisabled() { return (storage_class & STCdisable) != 0; }
|
||||
bool isOverride() { return (storage_class & STCoverride) != 0; }
|
||||
bool isResult() { return (storage_class & STCresult) != 0; }
|
||||
bool isField() { return (storage_class & STCfield) != 0; }
|
||||
bool isCtorinit() const { return (storage_class & STCctorinit) != 0; }
|
||||
bool isFinal() const { return (storage_class & STCfinal) != 0; }
|
||||
virtual bool isAbstract() { return (storage_class & STCabstract) != 0; }
|
||||
bool isConst() const { return (storage_class & STCconst) != 0; }
|
||||
bool isImmutable() const { return (storage_class & STCimmutable) != 0; }
|
||||
bool isWild() const { return (storage_class & STCwild) != 0; }
|
||||
bool isAuto() const { return (storage_class & STCauto) != 0; }
|
||||
bool isScope() const { return (storage_class & STCscope) != 0; }
|
||||
bool isSynchronized() const { return (storage_class & STCsynchronized) != 0; }
|
||||
bool isParameter() const { return (storage_class & STCparameter) != 0; }
|
||||
bool isDeprecated() const { return (storage_class & STCdeprecated) != 0; }
|
||||
bool isOverride() const { return (storage_class & STCoverride) != 0; }
|
||||
bool isResult() const { return (storage_class & STCresult) != 0; }
|
||||
bool isField() const { return (storage_class & STCfield) != 0; }
|
||||
|
||||
bool isIn() { return (storage_class & STCin) != 0; }
|
||||
bool isOut() { return (storage_class & STCout) != 0; }
|
||||
bool isRef() { return (storage_class & STCref) != 0; }
|
||||
bool isIn() const { return (storage_class & STCin) != 0; }
|
||||
bool isOut() const { return (storage_class & STCout) != 0; }
|
||||
bool isRef() const { return (storage_class & STCref) != 0; }
|
||||
bool isReference() const { return (storage_class & (STCref | STCout)) != 0; }
|
||||
|
||||
bool isFuture() { return (storage_class & STCfuture) != 0; }
|
||||
bool isFuture() const { return (storage_class & STCfuture) != 0; }
|
||||
|
||||
Prot prot();
|
||||
Visibility visible();
|
||||
|
||||
Declaration *isDeclaration() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -188,8 +169,7 @@ public:
|
|||
|
||||
TypeTuple *tupletype; // !=NULL if this is a type tuple
|
||||
|
||||
TupleDeclaration(Loc loc, Identifier *ident, Objects *objects);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
TupleDeclaration *syntaxCopy(Dsymbol *);
|
||||
const char *kind() const;
|
||||
Type *getType();
|
||||
Dsymbol *toAlias2();
|
||||
|
@ -208,16 +188,14 @@ public:
|
|||
Dsymbol *overnext; // next in overload list
|
||||
Dsymbol *_import; // !=NULL if unresolved internal alias for selective import
|
||||
|
||||
AliasDeclaration(Loc loc, Identifier *ident, Type *type);
|
||||
AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s);
|
||||
static AliasDeclaration *create(Loc loc, Identifier *id, Type *type);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
AliasDeclaration *syntaxCopy(Dsymbol *);
|
||||
bool overloadInsert(Dsymbol *s);
|
||||
const char *kind() const;
|
||||
Type *getType();
|
||||
Dsymbol *toAlias();
|
||||
Dsymbol *toAlias2();
|
||||
bool isOverloadable();
|
||||
bool isOverloadable() const;
|
||||
|
||||
AliasDeclaration *isAliasDeclaration() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -230,16 +208,14 @@ class OverDeclaration : public Declaration
|
|||
public:
|
||||
Dsymbol *overnext; // next in overload list
|
||||
Dsymbol *aliassym;
|
||||
bool hasOverloads;
|
||||
|
||||
OverDeclaration(Identifier *ident, Dsymbol *s, bool hasOverloads = true);
|
||||
const char *kind() const;
|
||||
bool equals(RootObject *o);
|
||||
bool equals(const RootObject *o) const;
|
||||
bool overloadInsert(Dsymbol *s);
|
||||
|
||||
Dsymbol *toAlias();
|
||||
Dsymbol *isUnique();
|
||||
bool isOverloadable();
|
||||
bool isOverloadable() const;
|
||||
|
||||
OverDeclaration *isOverDeclaration() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -251,33 +227,40 @@ class VarDeclaration : public Declaration
|
|||
{
|
||||
public:
|
||||
Initializer *_init;
|
||||
FuncDeclarations nestedrefs; // referenced by these lexically nested functions
|
||||
Dsymbol *aliassym; // if redone as alias to another symbol
|
||||
VarDeclaration *lastVar; // Linked list of variables for goto-skips-init detection
|
||||
Expression *edtor; // if !=NULL, does the destruction of the variable
|
||||
IntRange *range; // if !NULL, the variable is known to be within the range
|
||||
VarDeclarations *maybes; // STCmaybescope variables that are assigned to this STCmaybescope variable
|
||||
|
||||
unsigned endlinnum; // line number of end of scope that this var lives in
|
||||
unsigned offset;
|
||||
unsigned sequenceNumber; // order the variables are declared
|
||||
FuncDeclarations nestedrefs; // referenced by these lexically nested functions
|
||||
bool isargptr; // if parameter that _argptr points to
|
||||
structalign_t alignment;
|
||||
|
||||
// When interpreting, these point to the value (NULL if value not determinable)
|
||||
// The index of this variable on the CTFE stack, ~0u if not allocated
|
||||
unsigned ctfeAdrOnStack;
|
||||
|
||||
bool isargptr; // if parameter that _argptr points to
|
||||
bool ctorinit; // it has been initialized in a ctor
|
||||
bool iscatchvar; // this is the exception object variable in catch() clause
|
||||
bool isowner; // this is an Owner, despite it being `scope`
|
||||
bool onstack; // it is a class that was allocated on the stack
|
||||
bool mynew; // it is a class new'd with custom operator new
|
||||
int canassign; // it can be assigned to
|
||||
char canassign; // it can be assigned to
|
||||
bool overlapped; // if it is a field and has overlapping
|
||||
bool overlapUnsafe; // if it is an overlapping field and the overlaps are unsafe
|
||||
bool doNotInferScope; // do not infer 'scope' for this variable
|
||||
bool doNotInferReturn; // do not infer 'return' for this variable
|
||||
unsigned char isdataseg; // private data for isDataseg
|
||||
Dsymbol *aliassym; // if redone as alias to another symbol
|
||||
VarDeclaration *lastVar; // Linked list of variables for goto-skips-init detection
|
||||
unsigned endlinnum; // line number of end of scope that this var lives in
|
||||
bool isArgDtorVar; // temporary created to handle scope destruction of a function argument
|
||||
|
||||
// When interpreting, these point to the value (NULL if value not determinable)
|
||||
// The index of this variable on the CTFE stack, -1 if not allocated
|
||||
int ctfeAdrOnStack;
|
||||
Expression *edtor; // if !=NULL, does the destruction of the variable
|
||||
IntRange *range; // if !NULL, the variable is known to be within the range
|
||||
|
||||
VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init);
|
||||
static VarDeclaration *create(Loc loc, Type *t, Identifier *id, Initializer *init);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
|
||||
public:
|
||||
static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined);
|
||||
VarDeclaration *syntaxCopy(Dsymbol *);
|
||||
void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
|
||||
const char *kind() const;
|
||||
AggregateDeclaration *isThis();
|
||||
bool needThis();
|
||||
|
@ -291,11 +274,7 @@ public:
|
|||
bool canTakeAddressOf();
|
||||
bool needsScopeDtor();
|
||||
bool enclosesLifetimeOf(VarDeclaration *v) const;
|
||||
Expression *callScopeDtor(Scope *sc);
|
||||
Expression *getConstInitializer(bool needFullType = true);
|
||||
Expression *expandInitializer(Loc loc);
|
||||
void checkCtorConstInit();
|
||||
bool checkNestedReference(Scope *sc, Loc loc);
|
||||
Dsymbol *toAlias();
|
||||
// Eliminate need for dynamic_cast
|
||||
VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; }
|
||||
|
@ -304,6 +283,21 @@ public:
|
|||
|
||||
/**************************************************************/
|
||||
|
||||
class BitFieldDeclaration : public VarDeclaration
|
||||
{
|
||||
public:
|
||||
Expression *width;
|
||||
|
||||
unsigned fieldWidth;
|
||||
unsigned bitOffset;
|
||||
|
||||
BitFieldDeclaration *syntaxCopy(Dsymbol*);
|
||||
BitFieldDeclaration *isBitFieldDeclaration() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
// This is a shell around a back end symbol
|
||||
|
||||
class SymbolDeclaration : public Declaration
|
||||
|
@ -311,8 +305,6 @@ class SymbolDeclaration : public Declaration
|
|||
public:
|
||||
StructDeclaration *dsym;
|
||||
|
||||
SymbolDeclaration(Loc loc, StructDeclaration *dsym);
|
||||
|
||||
// Eliminate need for dynamic_cast
|
||||
SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -323,10 +315,9 @@ class TypeInfoDeclaration : public VarDeclaration
|
|||
public:
|
||||
Type *tinfo;
|
||||
|
||||
TypeInfoDeclaration(Type *tinfo);
|
||||
static TypeInfoDeclaration *create(Type *tinfo);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
const char *toChars();
|
||||
TypeInfoDeclaration *syntaxCopy(Dsymbol *);
|
||||
const char *toChars() const;
|
||||
|
||||
TypeInfoDeclaration *isTypeInfoDeclaration() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -335,7 +326,6 @@ public:
|
|||
class TypeInfoStructDeclaration : public TypeInfoDeclaration
|
||||
{
|
||||
public:
|
||||
TypeInfoStructDeclaration(Type *tinfo);
|
||||
static TypeInfoStructDeclaration *create(Type *tinfo);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -344,7 +334,6 @@ public:
|
|||
class TypeInfoClassDeclaration : public TypeInfoDeclaration
|
||||
{
|
||||
public:
|
||||
TypeInfoClassDeclaration(Type *tinfo);
|
||||
static TypeInfoClassDeclaration *create(Type *tinfo);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -353,7 +342,6 @@ public:
|
|||
class TypeInfoInterfaceDeclaration : public TypeInfoDeclaration
|
||||
{
|
||||
public:
|
||||
TypeInfoInterfaceDeclaration(Type *tinfo);
|
||||
static TypeInfoInterfaceDeclaration *create(Type *tinfo);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -362,7 +350,6 @@ public:
|
|||
class TypeInfoPointerDeclaration : public TypeInfoDeclaration
|
||||
{
|
||||
public:
|
||||
TypeInfoPointerDeclaration(Type *tinfo);
|
||||
static TypeInfoPointerDeclaration *create(Type *tinfo);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -371,7 +358,6 @@ public:
|
|||
class TypeInfoArrayDeclaration : public TypeInfoDeclaration
|
||||
{
|
||||
public:
|
||||
TypeInfoArrayDeclaration(Type *tinfo);
|
||||
static TypeInfoArrayDeclaration *create(Type *tinfo);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -380,7 +366,6 @@ public:
|
|||
class TypeInfoStaticArrayDeclaration : public TypeInfoDeclaration
|
||||
{
|
||||
public:
|
||||
TypeInfoStaticArrayDeclaration(Type *tinfo);
|
||||
static TypeInfoStaticArrayDeclaration *create(Type *tinfo);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -389,7 +374,6 @@ public:
|
|||
class TypeInfoAssociativeArrayDeclaration : public TypeInfoDeclaration
|
||||
{
|
||||
public:
|
||||
TypeInfoAssociativeArrayDeclaration(Type *tinfo);
|
||||
static TypeInfoAssociativeArrayDeclaration *create(Type *tinfo);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -398,7 +382,6 @@ public:
|
|||
class TypeInfoEnumDeclaration : public TypeInfoDeclaration
|
||||
{
|
||||
public:
|
||||
TypeInfoEnumDeclaration(Type *tinfo);
|
||||
static TypeInfoEnumDeclaration *create(Type *tinfo);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -407,7 +390,6 @@ public:
|
|||
class TypeInfoFunctionDeclaration : public TypeInfoDeclaration
|
||||
{
|
||||
public:
|
||||
TypeInfoFunctionDeclaration(Type *tinfo);
|
||||
static TypeInfoFunctionDeclaration *create(Type *tinfo);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -416,7 +398,6 @@ public:
|
|||
class TypeInfoDelegateDeclaration : public TypeInfoDeclaration
|
||||
{
|
||||
public:
|
||||
TypeInfoDelegateDeclaration(Type *tinfo);
|
||||
static TypeInfoDelegateDeclaration *create(Type *tinfo);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -425,7 +406,6 @@ public:
|
|||
class TypeInfoTupleDeclaration : public TypeInfoDeclaration
|
||||
{
|
||||
public:
|
||||
TypeInfoTupleDeclaration(Type *tinfo);
|
||||
static TypeInfoTupleDeclaration *create(Type *tinfo);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -434,7 +414,6 @@ public:
|
|||
class TypeInfoConstDeclaration : public TypeInfoDeclaration
|
||||
{
|
||||
public:
|
||||
TypeInfoConstDeclaration(Type *tinfo);
|
||||
static TypeInfoConstDeclaration *create(Type *tinfo);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -443,7 +422,6 @@ public:
|
|||
class TypeInfoInvariantDeclaration : public TypeInfoDeclaration
|
||||
{
|
||||
public:
|
||||
TypeInfoInvariantDeclaration(Type *tinfo);
|
||||
static TypeInfoInvariantDeclaration *create(Type *tinfo);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -452,7 +430,6 @@ public:
|
|||
class TypeInfoSharedDeclaration : public TypeInfoDeclaration
|
||||
{
|
||||
public:
|
||||
TypeInfoSharedDeclaration(Type *tinfo);
|
||||
static TypeInfoSharedDeclaration *create(Type *tinfo);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -461,7 +438,6 @@ public:
|
|||
class TypeInfoWildDeclaration : public TypeInfoDeclaration
|
||||
{
|
||||
public:
|
||||
TypeInfoWildDeclaration(Type *tinfo);
|
||||
static TypeInfoWildDeclaration *create(Type *tinfo);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -470,7 +446,6 @@ public:
|
|||
class TypeInfoVectorDeclaration : public TypeInfoDeclaration
|
||||
{
|
||||
public:
|
||||
TypeInfoVectorDeclaration(Type *tinfo);
|
||||
static TypeInfoVectorDeclaration *create(Type *tinfo);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -481,13 +456,12 @@ public:
|
|||
class ThisDeclaration : public VarDeclaration
|
||||
{
|
||||
public:
|
||||
ThisDeclaration(Loc loc, Type *t);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
ThisDeclaration *syntaxCopy(Dsymbol *);
|
||||
ThisDeclaration *isThisDeclaration() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
enum ILS
|
||||
enum class ILS : unsigned char
|
||||
{
|
||||
ILSuninitialized, // not computed yet
|
||||
ILSno, // cannot inline
|
||||
|
@ -496,68 +470,53 @@ enum ILS
|
|||
|
||||
/**************************************************************/
|
||||
|
||||
enum BUILTIN
|
||||
enum class BUILTIN : unsigned char
|
||||
{
|
||||
BUILTINunknown = 255, /// not known if this is a builtin
|
||||
BUILTINunimp = 0, /// this is not a builtin
|
||||
BUILTINgcc, /// this is a GCC builtin
|
||||
BUILTINllvm, /// this is an LLVM builtin
|
||||
BUILTINsin,
|
||||
BUILTINcos,
|
||||
BUILTINtan,
|
||||
BUILTINsqrt,
|
||||
BUILTINfabs,
|
||||
BUILTINldexp,
|
||||
BUILTINlog,
|
||||
BUILTINlog2,
|
||||
BUILTINlog10,
|
||||
BUILTINexp,
|
||||
BUILTINexpm1,
|
||||
BUILTINexp2,
|
||||
BUILTINround,
|
||||
BUILTINfloor,
|
||||
BUILTINceil,
|
||||
BUILTINtrunc,
|
||||
BUILTINcopysign,
|
||||
BUILTINpow,
|
||||
BUILTINfmin,
|
||||
BUILTINfmax,
|
||||
BUILTINfma,
|
||||
BUILTINisnan,
|
||||
BUILTINisinfinity,
|
||||
BUILTINisfinite,
|
||||
BUILTINbsf,
|
||||
BUILTINbsr,
|
||||
BUILTINbswap,
|
||||
BUILTINpopcnt,
|
||||
BUILTINyl2x,
|
||||
BUILTINyl2xp1,
|
||||
BUILTINtoPrecFloat,
|
||||
BUILTINtoPrecDouble,
|
||||
BUILTINtoPrecReal
|
||||
unknown = 255, /// not known if this is a builtin
|
||||
unimp = 0, /// this is not a builtin
|
||||
gcc, /// this is a GCC builtin
|
||||
llvm, /// this is an LLVM builtin
|
||||
sin,
|
||||
cos,
|
||||
tan,
|
||||
sqrt,
|
||||
fabs,
|
||||
ldexp,
|
||||
log,
|
||||
log2,
|
||||
log10,
|
||||
exp,
|
||||
expm1,
|
||||
exp2,
|
||||
round,
|
||||
floor,
|
||||
ceil,
|
||||
trunc,
|
||||
copysign,
|
||||
pow,
|
||||
fmin,
|
||||
fmax,
|
||||
fma,
|
||||
isnan,
|
||||
isinfinity,
|
||||
isfinite,
|
||||
bsf,
|
||||
bsr,
|
||||
bswap,
|
||||
popcnt,
|
||||
yl2x,
|
||||
yl2xp1,
|
||||
toPrecFloat,
|
||||
toPrecDouble,
|
||||
toPrecReal
|
||||
};
|
||||
|
||||
Expression *eval_builtin(Loc loc, FuncDeclaration *fd, Expressions *arguments);
|
||||
BUILTIN isBuiltin(FuncDeclaration *fd);
|
||||
|
||||
typedef Expression *(*builtin_fp)(Loc loc, FuncDeclaration *fd, Expressions *arguments);
|
||||
void add_builtin(const char *mangle, builtin_fp fp);
|
||||
void builtin_init();
|
||||
|
||||
#define FUNCFLAGpurityInprocess 1 // working on determining purity
|
||||
#define FUNCFLAGsafetyInprocess 2 // working on determining safety
|
||||
#define FUNCFLAGnothrowInprocess 4 // working on determining nothrow
|
||||
#define FUNCFLAGnogcInprocess 8 // working on determining @nogc
|
||||
#define FUNCFLAGreturnInprocess 0x10 // working on inferring 'return' for parameters
|
||||
#define FUNCFLAGinlineScanned 0x20 // function has been scanned for inline possibilities
|
||||
#define FUNCFLAGinferScope 0x40 // infer 'scope' for parameters
|
||||
#define FUNCFLAGprintf 0x200 // is a printf-like function
|
||||
#define FUNCFLAGscanf 0x400 // is a scanf-like function
|
||||
|
||||
class FuncDeclaration : public Declaration
|
||||
{
|
||||
public:
|
||||
Types *fthrows; // Array of Type's of exceptions (not used)
|
||||
Statements *frequires; // in contracts
|
||||
Ensures *fensures; // out contracts
|
||||
Statement *frequire; // lowered in contract
|
||||
|
@ -568,6 +527,9 @@ public:
|
|||
FuncDeclaration *fdrequire; // function that does the in contract
|
||||
FuncDeclaration *fdensure; // function that does the out contract
|
||||
|
||||
Expressions *fdrequireParams; // argument list for __require
|
||||
Expressions *fdensureParams; // argument list for __ensure
|
||||
|
||||
const char *mangleString; // mangled symbol created from mangleExact()
|
||||
|
||||
VarDeclaration *vresult; // result variable for out contracts
|
||||
|
@ -577,8 +539,9 @@ public:
|
|||
// scopes from having the same name
|
||||
DsymbolTable *localsymtab;
|
||||
VarDeclaration *vthis; // 'this' parameter (member and nested)
|
||||
bool isThis2; // has a dual-context 'this' parameter
|
||||
VarDeclaration *v_arguments; // '_arguments' parameter
|
||||
ObjcSelector* selector; // Objective-C method selector (member function only)
|
||||
|
||||
VarDeclaration *v_argptr; // '_argptr' variable
|
||||
VarDeclarations *parameters; // Array of VarDeclaration's for parameters
|
||||
DsymbolTable *labtab; // statement label symbol table
|
||||
|
@ -589,13 +552,16 @@ public:
|
|||
bool naked; // true if naked
|
||||
bool generated; // true if function was generated by the compiler rather than
|
||||
// supplied by the user
|
||||
bool hasAlwaysInlines; // contains references to functions that must be inlined
|
||||
unsigned char isCrtCtorDtor; // has attribute pragma(crt_constructor(1)/crt_destructor(2))
|
||||
// not set before the glue layer
|
||||
ILS inlineStatusStmt;
|
||||
ILS inlineStatusExp;
|
||||
PINLINE inlining;
|
||||
|
||||
CompiledCtfeFunction *ctfeCode; // Compiled code for interpreter
|
||||
int inlineNest; // !=0 if nested inline
|
||||
bool isArrayOp; // true if array operation
|
||||
bool eh_none; /// true if no exception unwinding is needed
|
||||
|
||||
// true if errors in semantic3 this function's frame ptr
|
||||
bool semantic3Errors;
|
||||
ForeachStatement *fes; // if foreach body, this is the foreach
|
||||
|
@ -635,6 +601,12 @@ public:
|
|||
|
||||
// local variables in this function which are referenced by nested functions
|
||||
VarDeclarations closureVars;
|
||||
|
||||
/** Outer variables which are referenced by this nested function
|
||||
* (the inverse of closureVars)
|
||||
*/
|
||||
VarDeclarations outerVars;
|
||||
|
||||
// Sibling nested functions which called this one
|
||||
FuncDeclarations siblingCallers;
|
||||
|
||||
|
@ -642,76 +614,62 @@ public:
|
|||
|
||||
unsigned flags; // FUNCFLAGxxxxx
|
||||
|
||||
FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type);
|
||||
static FuncDeclaration *create(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
// Data for a function declaration that is needed for the Objective-C
|
||||
// integration.
|
||||
ObjcFuncDeclaration objc;
|
||||
|
||||
static FuncDeclaration *create(const Loc &loc, const Loc &endloc, Identifier *id, StorageClass storage_class, Type *type, bool noreturn = false);
|
||||
FuncDeclaration *syntaxCopy(Dsymbol *);
|
||||
bool functionSemantic();
|
||||
bool functionSemantic3();
|
||||
bool checkForwardRef(Loc loc);
|
||||
// called from semantic3
|
||||
VarDeclaration *declareThis(Scope *sc, AggregateDeclaration *ad);
|
||||
bool equals(RootObject *o);
|
||||
bool equals(const RootObject *o) const;
|
||||
|
||||
int overrides(FuncDeclaration *fd);
|
||||
int findVtblIndex(Dsymbols *vtbl, int dim, bool fix17349 = true);
|
||||
int findVtblIndex(Dsymbols *vtbl, int dim);
|
||||
BaseClass *overrideInterface();
|
||||
bool overloadInsert(Dsymbol *s);
|
||||
FuncDeclaration *overloadExactMatch(Type *t);
|
||||
FuncDeclaration *overloadModMatch(Loc loc, Type *tthis, bool &hasOverloads);
|
||||
TemplateDeclaration *findTemplateDeclRoot();
|
||||
bool inUnittest();
|
||||
MATCH leastAsSpecialized(FuncDeclaration *g);
|
||||
LabelDsymbol *searchLabel(Identifier *ident);
|
||||
int getLevel(Loc loc, Scope *sc, FuncDeclaration *fd); // lexical nesting level difference
|
||||
LabelDsymbol *searchLabel(Identifier *ident, const Loc &loc);
|
||||
int getLevel(FuncDeclaration *fd, int intypeof); // lexical nesting level difference
|
||||
int getLevelAndCheck(const Loc &loc, Scope *sc, FuncDeclaration *fd);
|
||||
const char *toPrettyChars(bool QualifyTypes = false);
|
||||
const char *toFullSignature(); // for diagnostics, e.g. 'int foo(int x, int y) pure'
|
||||
bool isMain();
|
||||
bool isCMain();
|
||||
bool isWinMain();
|
||||
bool isDllMain();
|
||||
bool isMain() const;
|
||||
bool isCMain() const;
|
||||
bool isWinMain() const;
|
||||
bool isDllMain() const;
|
||||
bool isExport() const;
|
||||
bool isImportedSymbol() const;
|
||||
bool isCodeseg() const;
|
||||
bool isOverloadable();
|
||||
bool isOverloadable() const;
|
||||
bool isAbstract();
|
||||
PURE isPure();
|
||||
PURE isPureBypassingInference();
|
||||
bool setImpure();
|
||||
bool isSafe();
|
||||
bool isSafeBypassingInference();
|
||||
bool isTrusted();
|
||||
bool setUnsafe();
|
||||
|
||||
bool isNogc();
|
||||
bool isNogcBypassingInference();
|
||||
bool setGC();
|
||||
|
||||
void printGCUsage(Loc loc, const char *warn);
|
||||
bool isolateReturn();
|
||||
bool parametersIntersect(Type *t);
|
||||
virtual bool isNested();
|
||||
virtual bool isNested() const;
|
||||
AggregateDeclaration *isThis();
|
||||
bool needThis();
|
||||
bool isVirtualMethod();
|
||||
virtual bool isVirtual();
|
||||
virtual bool isFinalFunc();
|
||||
virtual bool isVirtual() const;
|
||||
bool isFinalFunc() const;
|
||||
virtual bool addPreInvariant();
|
||||
virtual bool addPostInvariant();
|
||||
const char *kind() const;
|
||||
FuncDeclaration *isUnique();
|
||||
bool checkNestedReference(Scope *sc, Loc loc);
|
||||
bool isUnique();
|
||||
bool needsClosure();
|
||||
bool checkClosure();
|
||||
bool hasNestedFrameRefs();
|
||||
void buildResultVar(Scope *sc, Type *tret);
|
||||
Statement *mergeFrequire(Statement *);
|
||||
static bool needsFensure(FuncDeclaration *fd);
|
||||
void buildEnsureRequire();
|
||||
Statement *mergeFensure(Statement *, Identifier *oid);
|
||||
ParameterList getParameterList();
|
||||
|
||||
static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0);
|
||||
static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc=0);
|
||||
void checkDmain();
|
||||
|
||||
bool checkNRVO();
|
||||
|
||||
FuncDeclaration *isFuncDeclaration() { return this; }
|
||||
|
@ -720,20 +678,12 @@ public:
|
|||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
|
||||
Objects *tiargs,
|
||||
Type *tthis,
|
||||
Expressions *arguments,
|
||||
int flags = 0);
|
||||
|
||||
class FuncAliasDeclaration : public FuncDeclaration
|
||||
{
|
||||
public:
|
||||
FuncDeclaration *funcalias;
|
||||
bool hasOverloads;
|
||||
|
||||
FuncAliasDeclaration(Identifier *ident, FuncDeclaration *funcalias, bool hasOverloads = true);
|
||||
|
||||
FuncAliasDeclaration *isFuncAliasDeclaration() { return this; }
|
||||
const char *kind() const;
|
||||
|
||||
|
@ -750,12 +700,10 @@ public:
|
|||
// backend
|
||||
bool deferToObj;
|
||||
|
||||
FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, TOK tok,
|
||||
ForeachStatement *fes, Identifier *id = NULL);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
bool isNested();
|
||||
FuncLiteralDeclaration *syntaxCopy(Dsymbol *);
|
||||
bool isNested() const;
|
||||
AggregateDeclaration *isThis();
|
||||
bool isVirtual();
|
||||
bool isVirtual() const;
|
||||
bool addPreInvariant();
|
||||
bool addPostInvariant();
|
||||
|
||||
|
@ -770,11 +718,11 @@ public:
|
|||
class CtorDeclaration : public FuncDeclaration
|
||||
{
|
||||
public:
|
||||
CtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Type *type);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
bool isCpCtor;
|
||||
CtorDeclaration *syntaxCopy(Dsymbol *);
|
||||
const char *kind() const;
|
||||
const char *toChars();
|
||||
bool isVirtual();
|
||||
const char *toChars() const;
|
||||
bool isVirtual() const;
|
||||
bool addPreInvariant();
|
||||
bool addPostInvariant();
|
||||
|
||||
|
@ -785,9 +733,8 @@ public:
|
|||
class PostBlitDeclaration : public FuncDeclaration
|
||||
{
|
||||
public:
|
||||
PostBlitDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
bool isVirtual();
|
||||
PostBlitDeclaration *syntaxCopy(Dsymbol *);
|
||||
bool isVirtual() const;
|
||||
bool addPreInvariant();
|
||||
bool addPostInvariant();
|
||||
bool overloadInsert(Dsymbol *s);
|
||||
|
@ -799,12 +746,10 @@ public:
|
|||
class DtorDeclaration : public FuncDeclaration
|
||||
{
|
||||
public:
|
||||
DtorDeclaration(Loc loc, Loc endloc);
|
||||
DtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
DtorDeclaration *syntaxCopy(Dsymbol *);
|
||||
const char *kind() const;
|
||||
const char *toChars();
|
||||
bool isVirtual();
|
||||
const char *toChars() const;
|
||||
bool isVirtual() const;
|
||||
bool addPreInvariant();
|
||||
bool addPostInvariant();
|
||||
bool overloadInsert(Dsymbol *s);
|
||||
|
@ -816,11 +761,9 @@ public:
|
|||
class StaticCtorDeclaration : public FuncDeclaration
|
||||
{
|
||||
public:
|
||||
StaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
|
||||
StaticCtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
StaticCtorDeclaration *syntaxCopy(Dsymbol *);
|
||||
AggregateDeclaration *isThis();
|
||||
bool isVirtual();
|
||||
bool isVirtual() const;
|
||||
bool addPreInvariant();
|
||||
bool addPostInvariant();
|
||||
bool hasStaticCtorOrDtor();
|
||||
|
@ -832,8 +775,7 @@ public:
|
|||
class SharedStaticCtorDeclaration : public StaticCtorDeclaration
|
||||
{
|
||||
public:
|
||||
SharedStaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
SharedStaticCtorDeclaration *syntaxCopy(Dsymbol *);
|
||||
|
||||
SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -844,11 +786,9 @@ class StaticDtorDeclaration : public FuncDeclaration
|
|||
public:
|
||||
VarDeclaration *vgate; // 'gate' variable
|
||||
|
||||
StaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
|
||||
StaticDtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
StaticDtorDeclaration *syntaxCopy(Dsymbol *);
|
||||
AggregateDeclaration *isThis();
|
||||
bool isVirtual();
|
||||
bool isVirtual() const;
|
||||
bool hasStaticCtorOrDtor();
|
||||
bool addPreInvariant();
|
||||
bool addPostInvariant();
|
||||
|
@ -860,8 +800,7 @@ public:
|
|||
class SharedStaticDtorDeclaration : public StaticDtorDeclaration
|
||||
{
|
||||
public:
|
||||
SharedStaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
SharedStaticDtorDeclaration *syntaxCopy(Dsymbol *);
|
||||
|
||||
SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
@ -870,9 +809,8 @@ public:
|
|||
class InvariantDeclaration : public FuncDeclaration
|
||||
{
|
||||
public:
|
||||
InvariantDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id = NULL);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
bool isVirtual();
|
||||
InvariantDeclaration *syntaxCopy(Dsymbol *);
|
||||
bool isVirtual() const;
|
||||
bool addPreInvariant();
|
||||
bool addPostInvariant();
|
||||
|
||||
|
@ -888,10 +826,9 @@ public:
|
|||
// toObjFile() these nested functions after this one
|
||||
FuncDeclarations deferredNested;
|
||||
|
||||
UnitTestDeclaration(Loc loc, Loc endloc, StorageClass stc, char *codedoc);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
UnitTestDeclaration *syntaxCopy(Dsymbol *);
|
||||
AggregateDeclaration *isThis();
|
||||
bool isVirtual();
|
||||
bool isVirtual() const;
|
||||
bool addPreInvariant();
|
||||
bool addPostInvariant();
|
||||
|
||||
|
@ -905,31 +842,12 @@ public:
|
|||
Parameters *parameters;
|
||||
VarArg varargs;
|
||||
|
||||
NewDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments, VarArg varargs);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
NewDeclaration *syntaxCopy(Dsymbol *);
|
||||
const char *kind() const;
|
||||
bool isVirtual();
|
||||
bool isVirtual() const;
|
||||
bool addPreInvariant();
|
||||
bool addPostInvariant();
|
||||
|
||||
NewDeclaration *isNewDeclaration() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
|
||||
class DeleteDeclaration : public FuncDeclaration
|
||||
{
|
||||
public:
|
||||
Parameters *parameters;
|
||||
|
||||
DeleteDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments);
|
||||
Dsymbol *syntaxCopy(Dsymbol *);
|
||||
const char *kind() const;
|
||||
bool isDelete();
|
||||
bool isVirtual();
|
||||
bool addPreInvariant();
|
||||
bool addPostInvariant();
|
||||
|
||||
DeleteDeclaration *isDeleteDeclaration() { return this; }
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
|
|
@ -1,208 +0,0 @@
|
|||
|
||||
/* Compiler implementation of the D programming language
|
||||
* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/D-Programming-Language/dmd/blob/master/src/delegatize.c
|
||||
*/
|
||||
|
||||
#include "root/dsystem.h"
|
||||
|
||||
#include "mars.h"
|
||||
#include "expression.h"
|
||||
#include "statement.h"
|
||||
#include "mtype.h"
|
||||
#include "utf.h"
|
||||
#include "declaration.h"
|
||||
#include "aggregate.h"
|
||||
#include "scope.h"
|
||||
#include "init.h"
|
||||
#include "tokens.h"
|
||||
|
||||
|
||||
bool walkPostorder(Expression *e, StoppableVisitor *v);
|
||||
void lambdaSetParent(Expression *e, Scope *sc);
|
||||
bool lambdaCheckForNestedRef(Expression *e, Scope *sc);
|
||||
|
||||
/********************************************
|
||||
* Convert from expression to delegate that returns the expression,
|
||||
* i.e. convert:
|
||||
* expr
|
||||
* to:
|
||||
* typeof(expr) delegate() { return expr; }
|
||||
*/
|
||||
Expression *toDelegate(Expression *e, Type* t, Scope *sc)
|
||||
{
|
||||
//printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), e->toChars());
|
||||
Loc loc = e->loc;
|
||||
|
||||
TypeFunction *tf = new TypeFunction(ParameterList(), t, LINKd);
|
||||
if (t->hasWild())
|
||||
tf->mod = MODwild;
|
||||
FuncLiteralDeclaration *fld =
|
||||
new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, NULL);
|
||||
|
||||
sc = sc->push();
|
||||
sc->parent = fld; // set current function to be the delegate
|
||||
lambdaSetParent(e, sc);
|
||||
bool r = lambdaCheckForNestedRef(e, sc);
|
||||
sc = sc->pop();
|
||||
|
||||
if (r)
|
||||
return new ErrorExp();
|
||||
|
||||
Statement *s;
|
||||
if (t->ty == Tvoid)
|
||||
s = new ExpStatement(loc, e);
|
||||
else
|
||||
s = new ReturnStatement(loc, e);
|
||||
fld->fbody = s;
|
||||
|
||||
e = new FuncExp(loc, fld);
|
||||
e = expressionSemantic(e, sc);
|
||||
return e;
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Patch the parent of declarations to be the new function literal.
|
||||
*/
|
||||
void lambdaSetParent(Expression *e, Scope *sc)
|
||||
{
|
||||
class LambdaSetParent : public StoppableVisitor
|
||||
{
|
||||
Scope *sc;
|
||||
public:
|
||||
LambdaSetParent(Scope *sc) : sc(sc) {}
|
||||
|
||||
void visit(Expression *)
|
||||
{
|
||||
}
|
||||
|
||||
void visit(DeclarationExp *e)
|
||||
{
|
||||
e->declaration->parent = sc->parent;
|
||||
}
|
||||
|
||||
void visit(IndexExp *e)
|
||||
{
|
||||
if (e->lengthVar)
|
||||
{
|
||||
//printf("lengthVar\n");
|
||||
e->lengthVar->parent = sc->parent;
|
||||
}
|
||||
}
|
||||
|
||||
void visit(SliceExp *e)
|
||||
{
|
||||
if (e->lengthVar)
|
||||
{
|
||||
//printf("lengthVar\n");
|
||||
e->lengthVar->parent = sc->parent;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
LambdaSetParent lsp(sc);
|
||||
walkPostorder(e, &lsp);
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
* Look for references to variables in a scope enclosing the new function literal.
|
||||
* Returns true if error occurs.
|
||||
*/
|
||||
bool lambdaCheckForNestedRef(Expression *e, Scope *sc)
|
||||
{
|
||||
class LambdaCheckForNestedRef : public StoppableVisitor
|
||||
{
|
||||
public:
|
||||
Scope *sc;
|
||||
bool result;
|
||||
|
||||
LambdaCheckForNestedRef(Scope *sc)
|
||||
: sc(sc), result(false)
|
||||
{
|
||||
}
|
||||
|
||||
void visit(Expression *)
|
||||
{
|
||||
}
|
||||
|
||||
void visit(SymOffExp *e)
|
||||
{
|
||||
VarDeclaration *v = e->var->isVarDeclaration();
|
||||
if (v)
|
||||
result = v->checkNestedReference(sc, Loc());
|
||||
}
|
||||
|
||||
void visit(VarExp *e)
|
||||
{
|
||||
VarDeclaration *v = e->var->isVarDeclaration();
|
||||
if (v)
|
||||
result = v->checkNestedReference(sc, Loc());
|
||||
}
|
||||
|
||||
void visit(ThisExp *e)
|
||||
{
|
||||
if (e->var)
|
||||
result = e->var->checkNestedReference(sc, Loc());
|
||||
}
|
||||
|
||||
void visit(DeclarationExp *e)
|
||||
{
|
||||
VarDeclaration *v = e->declaration->isVarDeclaration();
|
||||
if (v)
|
||||
{
|
||||
result = v->checkNestedReference(sc, Loc());
|
||||
if (result)
|
||||
return;
|
||||
|
||||
/* Some expressions cause the frontend to create a temporary.
|
||||
* For example, structs with cpctors replace the original
|
||||
* expression e with:
|
||||
* __cpcttmp = __cpcttmp.cpctor(e);
|
||||
*
|
||||
* In this instance, we need to ensure that the original
|
||||
* expression e does not have any nested references by
|
||||
* checking the declaration initializer too.
|
||||
*/
|
||||
if (v->_init && v->_init->isExpInitializer())
|
||||
{
|
||||
Expression *ie = initializerToExpression(v->_init);
|
||||
result = lambdaCheckForNestedRef(ie, sc);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
LambdaCheckForNestedRef v(sc);
|
||||
walkPostorder(e, &v);
|
||||
return v.result;
|
||||
}
|
||||
|
||||
bool checkNestedRef(Dsymbol *s, Dsymbol *p)
|
||||
{
|
||||
while (s)
|
||||
{
|
||||
if (s == p) // hit!
|
||||
return false;
|
||||
|
||||
if (FuncDeclaration *fd = s->isFuncDeclaration())
|
||||
{
|
||||
if (!fd->isThis() && !fd->isNested())
|
||||
break;
|
||||
|
||||
// Bugzilla 15332: change to delegate if fd is actually nested.
|
||||
if (FuncLiteralDeclaration *fld = fd->isFuncLiteralDeclaration())
|
||||
fld->tok = TOKdelegate;
|
||||
}
|
||||
if (AggregateDeclaration *ad = s->isAggregateDeclaration())
|
||||
{
|
||||
if (ad->storage_class & STCstatic)
|
||||
break;
|
||||
}
|
||||
s = s->toParent2();
|
||||
}
|
||||
return true;
|
||||
}
|
305
gcc/d/dmd/delegatize.d
Normal file
305
gcc/d/dmd/delegatize.d
Normal file
|
@ -0,0 +1,305 @@
|
|||
/**
|
||||
* Implements conversion from expressions to delegates for lazy parameters.
|
||||
*
|
||||
* Specification: $(LINK2 https://dlang.org/spec/function.html#lazy-params, Lazy Parameters)
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/delegatize.d, _delegatize.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_delegatize.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/delegatize.d
|
||||
*/
|
||||
|
||||
module dmd.delegatize;
|
||||
|
||||
import core.stdc.stdio;
|
||||
import dmd.apply;
|
||||
import dmd.astenums;
|
||||
import dmd.declaration;
|
||||
import dmd.dscope;
|
||||
import dmd.dsymbol;
|
||||
import dmd.expression;
|
||||
import dmd.expressionsem;
|
||||
import dmd.func;
|
||||
import dmd.globals;
|
||||
import dmd.init;
|
||||
import dmd.initsem;
|
||||
import dmd.mtype;
|
||||
import dmd.statement;
|
||||
import dmd.tokens;
|
||||
import dmd.visitor;
|
||||
|
||||
|
||||
/*********************************
|
||||
* Convert expression into a delegate.
|
||||
*
|
||||
* Used to convert the argument to a lazy parameter.
|
||||
*
|
||||
* Params:
|
||||
* e = argument to convert to a delegate
|
||||
* t = the type to be returned by the delegate
|
||||
* sc = context
|
||||
* Returns:
|
||||
* A delegate literal
|
||||
*/
|
||||
Expression toDelegate(Expression e, Type t, Scope* sc)
|
||||
{
|
||||
//printf("Expression::toDelegate(t = %s) %s\n", t.toChars(), e.toChars());
|
||||
Loc loc = e.loc;
|
||||
auto tf = new TypeFunction(ParameterList(), t, LINK.d);
|
||||
if (t.hasWild())
|
||||
tf.mod = MODFlags.wild;
|
||||
auto fld = new FuncLiteralDeclaration(loc, loc, tf, TOK.delegate_, null);
|
||||
lambdaSetParent(e, fld);
|
||||
|
||||
sc = sc.push();
|
||||
sc.parent = fld; // set current function to be the delegate
|
||||
bool r = lambdaCheckForNestedRef(e, sc);
|
||||
sc = sc.pop();
|
||||
if (r)
|
||||
return ErrorExp.get();
|
||||
|
||||
Statement s;
|
||||
if (t.ty == Tvoid)
|
||||
s = new ExpStatement(loc, e);
|
||||
else
|
||||
s = new ReturnStatement(loc, e);
|
||||
fld.fbody = s;
|
||||
e = new FuncExp(loc, fld);
|
||||
e = e.expressionSemantic(sc);
|
||||
return e;
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Patch the parent of declarations to be the new function literal.
|
||||
*
|
||||
* Since the expression is going to be moved into a function literal,
|
||||
* the parent for declarations in the expression needs to be
|
||||
* reset to that function literal.
|
||||
* Params:
|
||||
* e = expression to check
|
||||
* fd = function literal symbol (the new parent)
|
||||
*/
|
||||
private void lambdaSetParent(Expression e, FuncDeclaration fd)
|
||||
{
|
||||
extern (C++) final class LambdaSetParent : StoppableVisitor
|
||||
{
|
||||
alias visit = typeof(super).visit;
|
||||
FuncDeclaration fd;
|
||||
|
||||
private void setParent(Dsymbol s)
|
||||
{
|
||||
VarDeclaration vd = s.isVarDeclaration();
|
||||
FuncDeclaration pfd = s.parent ? s.parent.isFuncDeclaration() : null;
|
||||
s.parent = fd;
|
||||
if (!vd || !pfd)
|
||||
return;
|
||||
// move to fd's closure when applicable
|
||||
foreach (i; 0 .. pfd.closureVars.dim)
|
||||
{
|
||||
if (vd == pfd.closureVars[i])
|
||||
{
|
||||
pfd.closureVars.remove(i);
|
||||
fd.closureVars.push(vd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
extern (D) this(FuncDeclaration fd)
|
||||
{
|
||||
this.fd = fd;
|
||||
}
|
||||
|
||||
override void visit(Expression)
|
||||
{
|
||||
}
|
||||
|
||||
override void visit(DeclarationExp e)
|
||||
{
|
||||
setParent(e.declaration);
|
||||
e.declaration.accept(this);
|
||||
}
|
||||
|
||||
override void visit(IndexExp e)
|
||||
{
|
||||
if (e.lengthVar)
|
||||
{
|
||||
//printf("lengthVar\n");
|
||||
setParent(e.lengthVar);
|
||||
e.lengthVar.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(SliceExp e)
|
||||
{
|
||||
if (e.lengthVar)
|
||||
{
|
||||
//printf("lengthVar\n");
|
||||
setParent(e.lengthVar);
|
||||
e.lengthVar.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(Dsymbol)
|
||||
{
|
||||
}
|
||||
|
||||
override void visit(VarDeclaration v)
|
||||
{
|
||||
if (v._init)
|
||||
v._init.accept(this);
|
||||
}
|
||||
|
||||
override void visit(Initializer)
|
||||
{
|
||||
}
|
||||
|
||||
override void visit(ExpInitializer ei)
|
||||
{
|
||||
walkPostorder(ei.exp ,this);
|
||||
}
|
||||
|
||||
override void visit(StructInitializer si)
|
||||
{
|
||||
foreach (i, const id; si.field)
|
||||
if (Initializer iz = si.value[i])
|
||||
iz.accept(this);
|
||||
}
|
||||
|
||||
override void visit(ArrayInitializer ai)
|
||||
{
|
||||
foreach (i, ex; ai.index)
|
||||
{
|
||||
if (ex)
|
||||
walkPostorder(ex, this);
|
||||
if (Initializer iz = ai.value[i])
|
||||
iz.accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope LambdaSetParent lsp = new LambdaSetParent(fd);
|
||||
walkPostorder(e, lsp);
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
* Look for references to variables in a scope enclosing the new function literal.
|
||||
*
|
||||
* Essentially just calls `checkNestedReference() for each variable reference in `e`.
|
||||
* Params:
|
||||
* sc = context
|
||||
* e = expression to check
|
||||
* Returns:
|
||||
* true if error occurs.
|
||||
*/
|
||||
bool lambdaCheckForNestedRef(Expression e, Scope* sc)
|
||||
{
|
||||
extern (C++) final class LambdaCheckForNestedRef : StoppableVisitor
|
||||
{
|
||||
alias visit = typeof(super).visit;
|
||||
public:
|
||||
Scope* sc;
|
||||
bool result;
|
||||
|
||||
extern (D) this(Scope* sc)
|
||||
{
|
||||
this.sc = sc;
|
||||
}
|
||||
|
||||
override void visit(Expression)
|
||||
{
|
||||
}
|
||||
|
||||
override void visit(SymOffExp e)
|
||||
{
|
||||
VarDeclaration v = e.var.isVarDeclaration();
|
||||
if (v)
|
||||
result = v.checkNestedReference(sc, Loc.initial);
|
||||
}
|
||||
|
||||
override void visit(VarExp e)
|
||||
{
|
||||
VarDeclaration v = e.var.isVarDeclaration();
|
||||
if (v)
|
||||
result = v.checkNestedReference(sc, Loc.initial);
|
||||
}
|
||||
|
||||
override void visit(ThisExp e)
|
||||
{
|
||||
if (e.var)
|
||||
result = e.var.checkNestedReference(sc, Loc.initial);
|
||||
}
|
||||
|
||||
override void visit(DeclarationExp e)
|
||||
{
|
||||
VarDeclaration v = e.declaration.isVarDeclaration();
|
||||
if (v)
|
||||
{
|
||||
result = v.checkNestedReference(sc, Loc.initial);
|
||||
if (result)
|
||||
return;
|
||||
/* Some expressions cause the frontend to create a temporary.
|
||||
* For example, structs with cpctors replace the original
|
||||
* expression e with:
|
||||
* __cpcttmp = __cpcttmp.cpctor(e);
|
||||
*
|
||||
* In this instance, we need to ensure that the original
|
||||
* expression e does not have any nested references by
|
||||
* checking the declaration initializer too.
|
||||
*/
|
||||
if (v._init && v._init.isExpInitializer())
|
||||
{
|
||||
Expression ie = v._init.initializerToExpression();
|
||||
result = lambdaCheckForNestedRef(ie, sc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope LambdaCheckForNestedRef v = new LambdaCheckForNestedRef(sc);
|
||||
walkPostorder(e, v);
|
||||
return v.result;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* See if context `s` is nested within context `p`, meaning
|
||||
* it `p` is reachable at runtime by walking the static links.
|
||||
* If any of the intervening contexts are function literals,
|
||||
* make sure they are delegates.
|
||||
* Params:
|
||||
* s = inner context
|
||||
* p = outer context
|
||||
* Returns:
|
||||
* true means it is accessible by walking the context pointers at runtime
|
||||
* References:
|
||||
* for static links see https://en.wikipedia.org/wiki/Call_stack#Functions_of_the_call_stack
|
||||
*/
|
||||
bool ensureStaticLinkTo(Dsymbol s, Dsymbol p)
|
||||
{
|
||||
while (s)
|
||||
{
|
||||
if (s == p) // hit!
|
||||
return true;
|
||||
|
||||
if (auto fd = s.isFuncDeclaration())
|
||||
{
|
||||
if (!fd.isThis() && !fd.isNested())
|
||||
break;
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=15332
|
||||
// change to delegate if fd is actually nested.
|
||||
if (auto fld = fd.isFuncLiteralDeclaration())
|
||||
fld.tok = TOK.delegate_;
|
||||
}
|
||||
if (auto ad = s.isAggregateDeclaration())
|
||||
{
|
||||
if (ad.storage_class & STC.static_)
|
||||
break;
|
||||
}
|
||||
s = s.toParentP(p);
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -1,388 +0,0 @@
|
|||
|
||||
/* Compiler implementation of the D programming language
|
||||
* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/D-Programming-Language/dmd/blob/master/src/enum.c
|
||||
*/
|
||||
|
||||
#include "root/dsystem.h"
|
||||
#include "root/root.h"
|
||||
|
||||
#include "errors.h"
|
||||
#include "enum.h"
|
||||
#include "attrib.h"
|
||||
#include "mtype.h"
|
||||
#include "scope.h"
|
||||
#include "id.h"
|
||||
#include "expression.h"
|
||||
#include "module.h"
|
||||
#include "declaration.h"
|
||||
#include "init.h"
|
||||
|
||||
bool isSpecialEnumIdent(const Identifier *ident)
|
||||
{
|
||||
return ident == Id::__c_long ||
|
||||
ident == Id::__c_ulong ||
|
||||
ident == Id::__c_longlong ||
|
||||
ident == Id::__c_ulonglong ||
|
||||
ident == Id::__c_long_double ||
|
||||
ident == Id::__c_wchar_t ||
|
||||
ident == Id::__c_complex_float ||
|
||||
ident == Id::__c_complex_double ||
|
||||
ident == Id::__c_complex_real;
|
||||
}
|
||||
|
||||
/********************************* EnumDeclaration ****************************/
|
||||
|
||||
EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype)
|
||||
: ScopeDsymbol(id)
|
||||
{
|
||||
//printf("EnumDeclaration() %s\n", toChars());
|
||||
this->loc = loc;
|
||||
type = new TypeEnum(this);
|
||||
this->memtype = memtype;
|
||||
maxval = NULL;
|
||||
minval = NULL;
|
||||
defaultval = NULL;
|
||||
sinit = NULL;
|
||||
isdeprecated = false;
|
||||
protection = Prot(Prot::undefined);
|
||||
parent = NULL;
|
||||
added = false;
|
||||
inuse = 0;
|
||||
}
|
||||
|
||||
Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s)
|
||||
{
|
||||
assert(!s);
|
||||
EnumDeclaration *ed = new EnumDeclaration(loc, ident,
|
||||
memtype ? memtype->syntaxCopy() : NULL);
|
||||
return ScopeDsymbol::syntaxCopy(ed);
|
||||
}
|
||||
|
||||
void EnumDeclaration::setScope(Scope *sc)
|
||||
{
|
||||
if (semanticRun > PASSinit)
|
||||
return;
|
||||
ScopeDsymbol::setScope(sc);
|
||||
}
|
||||
|
||||
void EnumDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
|
||||
{
|
||||
/* Anonymous enum members get added to enclosing scope.
|
||||
*/
|
||||
ScopeDsymbol *scopesym = isAnonymous() ? sds : this;
|
||||
|
||||
if (!isAnonymous())
|
||||
{
|
||||
ScopeDsymbol::addMember(sc, sds);
|
||||
|
||||
if (!symtab)
|
||||
symtab = new DsymbolTable();
|
||||
}
|
||||
|
||||
if (members)
|
||||
{
|
||||
for (size_t i = 0; i < members->length; i++)
|
||||
{
|
||||
EnumMember *em = (*members)[i]->isEnumMember();
|
||||
em->ed = this;
|
||||
//printf("add %s to scope %s\n", em->toChars(), scopesym->toChars());
|
||||
em->addMember(sc, isAnonymous() ? scopesym : this);
|
||||
}
|
||||
}
|
||||
added = true;
|
||||
}
|
||||
|
||||
/******************************
|
||||
* Get the value of the .max/.min property as an Expression
|
||||
* Input:
|
||||
* id Id::max or Id::min
|
||||
*/
|
||||
|
||||
Expression *EnumDeclaration::getMaxMinValue(Loc loc, Identifier *id)
|
||||
{
|
||||
//printf("EnumDeclaration::getMaxValue()\n");
|
||||
bool first = true;
|
||||
|
||||
Expression **pval = (id == Id::max) ? &maxval : &minval;
|
||||
|
||||
if (inuse)
|
||||
{
|
||||
error(loc, "recursive definition of .%s property", id->toChars());
|
||||
goto Lerrors;
|
||||
}
|
||||
if (*pval)
|
||||
goto Ldone;
|
||||
|
||||
if (_scope)
|
||||
dsymbolSemantic(this, _scope);
|
||||
if (errors)
|
||||
goto Lerrors;
|
||||
if (!members)
|
||||
{
|
||||
if (isSpecial())
|
||||
{
|
||||
/* Allow these special enums to not need a member list
|
||||
*/
|
||||
return memtype->getProperty(loc, id, 0);
|
||||
}
|
||||
|
||||
error(loc, "is opaque and has no `.%s`", id->toChars());
|
||||
goto Lerrors;
|
||||
}
|
||||
if (!(memtype && memtype->isintegral()))
|
||||
{
|
||||
error(loc, "has no .%s property because base type %s is not an integral type",
|
||||
id->toChars(),
|
||||
memtype ? memtype->toChars() : "");
|
||||
goto Lerrors;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < members->length; i++)
|
||||
{
|
||||
EnumMember *em = (*members)[i]->isEnumMember();
|
||||
if (!em)
|
||||
continue;
|
||||
if (em->errors)
|
||||
{
|
||||
errors = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (em->semanticRun < PASSsemanticdone)
|
||||
{
|
||||
em->error("is forward referenced looking for `.%s`", id->toChars());
|
||||
errors = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (first)
|
||||
{
|
||||
*pval = em->value();
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* In order to work successfully with UDTs,
|
||||
* build expressions to do the comparisons,
|
||||
* and let the semantic analyzer and constant
|
||||
* folder give us the result.
|
||||
*/
|
||||
|
||||
/* Compute:
|
||||
* if (e > maxval)
|
||||
* maxval = e;
|
||||
*/
|
||||
Expression *e = em->value();
|
||||
Expression *ec = new CmpExp(id == Id::max ? TOKgt : TOKlt, em->loc, e, *pval);
|
||||
inuse++;
|
||||
ec = expressionSemantic(ec, em->_scope);
|
||||
inuse--;
|
||||
ec = ec->ctfeInterpret();
|
||||
if (ec->op == TOKerror)
|
||||
{
|
||||
errors = true;
|
||||
continue;
|
||||
}
|
||||
if (ec->toInteger())
|
||||
*pval = e;
|
||||
}
|
||||
}
|
||||
if (errors)
|
||||
goto Lerrors;
|
||||
Ldone:
|
||||
{
|
||||
Expression *e = *pval;
|
||||
if (e->op != TOKerror)
|
||||
{
|
||||
e = e->copy();
|
||||
e->loc = loc;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
Lerrors:
|
||||
*pval = new ErrorExp();
|
||||
return *pval;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Determine if enum is a 'special' one.
|
||||
* Returns:
|
||||
* true if special
|
||||
*/
|
||||
bool EnumDeclaration::isSpecial() const
|
||||
{
|
||||
return isSpecialEnumIdent(ident) && memtype;
|
||||
}
|
||||
|
||||
Expression *EnumDeclaration::getDefaultValue(Loc loc)
|
||||
{
|
||||
//printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars());
|
||||
if (defaultval)
|
||||
return defaultval;
|
||||
|
||||
if (_scope)
|
||||
dsymbolSemantic(this, _scope);
|
||||
if (errors)
|
||||
goto Lerrors;
|
||||
if (!members)
|
||||
{
|
||||
if (isSpecial())
|
||||
{
|
||||
/* Allow these special enums to not need a member list
|
||||
*/
|
||||
defaultval = memtype->defaultInit(loc);
|
||||
return defaultval;
|
||||
}
|
||||
|
||||
error(loc, "is opaque and has no default initializer");
|
||||
goto Lerrors;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < members->length; i++)
|
||||
{
|
||||
EnumMember *em = (*members)[i]->isEnumMember();
|
||||
if (em)
|
||||
{
|
||||
if (em->semanticRun < PASSsemanticdone)
|
||||
{
|
||||
error(loc, "forward reference of `%s.init`", toChars());
|
||||
goto Lerrors;
|
||||
}
|
||||
|
||||
defaultval = em->value();
|
||||
return defaultval;
|
||||
}
|
||||
}
|
||||
|
||||
Lerrors:
|
||||
defaultval = new ErrorExp();
|
||||
return defaultval;
|
||||
}
|
||||
|
||||
Type *EnumDeclaration::getMemtype(Loc loc)
|
||||
{
|
||||
if (loc.linnum == 0)
|
||||
loc = this->loc;
|
||||
if (_scope)
|
||||
{
|
||||
/* Enum is forward referenced. We don't need to resolve the whole thing,
|
||||
* just the base type
|
||||
*/
|
||||
if (memtype)
|
||||
memtype = typeSemantic(memtype, loc, _scope);
|
||||
}
|
||||
if (!memtype)
|
||||
{
|
||||
if (!isAnonymous() && (members || semanticRun >= PASSsemanticdone))
|
||||
memtype = Type::tint32;
|
||||
else
|
||||
{
|
||||
error(loc, "is forward referenced looking for base type");
|
||||
return Type::terror;
|
||||
}
|
||||
}
|
||||
return memtype;
|
||||
}
|
||||
|
||||
bool EnumDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
|
||||
{
|
||||
if (isAnonymous())
|
||||
return Dsymbol::oneMembers(members, ps, ident);
|
||||
return Dsymbol::oneMember(ps, ident);
|
||||
}
|
||||
|
||||
Type *EnumDeclaration::getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
const char *EnumDeclaration::kind() const
|
||||
{
|
||||
return "enum";
|
||||
}
|
||||
|
||||
bool EnumDeclaration::isDeprecated()
|
||||
{
|
||||
return isdeprecated;
|
||||
}
|
||||
|
||||
Prot EnumDeclaration::prot()
|
||||
{
|
||||
return protection;
|
||||
}
|
||||
|
||||
Dsymbol *EnumDeclaration::search(const Loc &loc, Identifier *ident, int flags)
|
||||
{
|
||||
//printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars());
|
||||
if (_scope)
|
||||
{
|
||||
// Try one last time to resolve this enum
|
||||
dsymbolSemantic(this, _scope);
|
||||
}
|
||||
|
||||
Dsymbol *s = ScopeDsymbol::search(loc, ident, flags);
|
||||
return s;
|
||||
}
|
||||
|
||||
/********************************* EnumMember ****************************/
|
||||
|
||||
EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *origType)
|
||||
: VarDeclaration(loc, NULL, id ? id : Id::empty, new ExpInitializer(loc, value))
|
||||
{
|
||||
this->ed = NULL;
|
||||
this->origValue = value;
|
||||
this->origType = origType;
|
||||
}
|
||||
|
||||
EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *memType,
|
||||
StorageClass stc, UserAttributeDeclaration *uad, DeprecatedDeclaration *dd)
|
||||
: VarDeclaration(loc, NULL, id ? id : Id::empty, new ExpInitializer(loc, value))
|
||||
{
|
||||
this->ed = NULL;
|
||||
this->origValue = value;
|
||||
this->origType = memType;
|
||||
this->storage_class = stc;
|
||||
this->userAttribDecl = uad;
|
||||
this->depdecl = dd;
|
||||
}
|
||||
|
||||
Expression *&EnumMember::value()
|
||||
{
|
||||
return ((ExpInitializer*)_init)->exp;
|
||||
}
|
||||
|
||||
Dsymbol *EnumMember::syntaxCopy(Dsymbol *s)
|
||||
{
|
||||
assert(!s);
|
||||
return new EnumMember(loc, ident,
|
||||
value() ? value()->syntaxCopy() : NULL,
|
||||
origType ? origType->syntaxCopy() : NULL);
|
||||
}
|
||||
|
||||
const char *EnumMember::kind() const
|
||||
{
|
||||
return "enum member";
|
||||
}
|
||||
|
||||
Expression *EnumMember::getVarExp(Loc loc, Scope *sc)
|
||||
{
|
||||
dsymbolSemantic(this, sc);
|
||||
if (errors)
|
||||
return new ErrorExp();
|
||||
checkDisabled(loc, sc);
|
||||
|
||||
if (depdecl && !depdecl->_scope)
|
||||
depdecl->_scope = sc;
|
||||
checkDeprecated(loc, sc);
|
||||
|
||||
if (errors)
|
||||
return new ErrorExp();
|
||||
Expression *e = new VarExp(loc, this);
|
||||
return expressionSemantic(e, sc);
|
||||
}
|
333
gcc/d/dmd/denum.d
Normal file
333
gcc/d/dmd/denum.d
Normal file
|
@ -0,0 +1,333 @@
|
|||
/**
|
||||
* Define `enum` declarations and `enum` members.
|
||||
*
|
||||
* Specification: $(LINK2 https://dlang.org/spec/enum.html, Enums)
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/denum.d, _denum.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_denum.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/denum.d
|
||||
* References: https://dlang.org/spec/enum.html
|
||||
*/
|
||||
|
||||
module dmd.denum;
|
||||
|
||||
import core.stdc.stdio;
|
||||
|
||||
import dmd.attrib;
|
||||
import dmd.gluelayer;
|
||||
import dmd.declaration;
|
||||
import dmd.dscope;
|
||||
import dmd.dsymbol;
|
||||
import dmd.dsymbolsem;
|
||||
import dmd.expression;
|
||||
import dmd.globals;
|
||||
import dmd.id;
|
||||
import dmd.identifier;
|
||||
import dmd.init;
|
||||
import dmd.mtype;
|
||||
import dmd.tokens;
|
||||
import dmd.typesem;
|
||||
import dmd.visitor;
|
||||
|
||||
/***********************************************************
|
||||
* AST node for `EnumDeclaration`
|
||||
* https://dlang.org/spec/enum.html#EnumDeclaration
|
||||
*/
|
||||
extern (C++) final class EnumDeclaration : ScopeDsymbol
|
||||
{
|
||||
/* The separate, and distinct, cases are:
|
||||
* 1. enum { ... }
|
||||
* 2. enum : memtype { ... }
|
||||
* 3. enum id { ... }
|
||||
* 4. enum id : memtype { ... }
|
||||
* 5. enum id : memtype;
|
||||
* 6. enum id;
|
||||
*/
|
||||
Type type; // the TypeEnum
|
||||
Type memtype; // type of the members
|
||||
|
||||
Visibility visibility;
|
||||
Expression maxval;
|
||||
Expression minval;
|
||||
Expression defaultval; // default initializer
|
||||
bool isdeprecated;
|
||||
bool added;
|
||||
int inuse;
|
||||
|
||||
extern (D) this(const ref Loc loc, Identifier ident, Type memtype)
|
||||
{
|
||||
super(loc, ident);
|
||||
//printf("EnumDeclaration() %s\n", toChars());
|
||||
type = new TypeEnum(this);
|
||||
this.memtype = memtype;
|
||||
visibility = Visibility(Visibility.Kind.undefined);
|
||||
}
|
||||
|
||||
override EnumDeclaration syntaxCopy(Dsymbol s)
|
||||
{
|
||||
assert(!s);
|
||||
auto ed = new EnumDeclaration(loc, ident, memtype ? memtype.syntaxCopy() : null);
|
||||
ScopeDsymbol.syntaxCopy(ed);
|
||||
return ed;
|
||||
}
|
||||
|
||||
override void addMember(Scope* sc, ScopeDsymbol sds)
|
||||
{
|
||||
version (none)
|
||||
{
|
||||
printf("EnumDeclaration::addMember() %s\n", toChars());
|
||||
for (size_t i = 0; i < members.dim; i++)
|
||||
{
|
||||
EnumMember em = (*members)[i].isEnumMember();
|
||||
printf(" member %s\n", em.toChars());
|
||||
}
|
||||
}
|
||||
if (!isAnonymous())
|
||||
{
|
||||
ScopeDsymbol.addMember(sc, sds);
|
||||
}
|
||||
|
||||
addEnumMembers(this, sc, sds);
|
||||
}
|
||||
|
||||
override void setScope(Scope* sc)
|
||||
{
|
||||
if (semanticRun > PASS.init)
|
||||
return;
|
||||
ScopeDsymbol.setScope(sc);
|
||||
}
|
||||
|
||||
override bool oneMember(Dsymbol* ps, Identifier ident)
|
||||
{
|
||||
if (isAnonymous())
|
||||
return Dsymbol.oneMembers(members, ps, ident);
|
||||
return Dsymbol.oneMember(ps, ident);
|
||||
}
|
||||
|
||||
override Type getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
override const(char)* kind() const
|
||||
{
|
||||
return "enum";
|
||||
}
|
||||
|
||||
override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
|
||||
{
|
||||
//printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident.toChars());
|
||||
if (_scope)
|
||||
{
|
||||
// Try one last time to resolve this enum
|
||||
dsymbolSemantic(this, _scope);
|
||||
}
|
||||
|
||||
Dsymbol s = ScopeDsymbol.search(loc, ident, flags);
|
||||
return s;
|
||||
}
|
||||
|
||||
// is Dsymbol deprecated?
|
||||
override bool isDeprecated() const
|
||||
{
|
||||
return isdeprecated;
|
||||
}
|
||||
|
||||
override Visibility visible() pure nothrow @nogc @safe
|
||||
{
|
||||
return visibility;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Determine if enum is a special one.
|
||||
* Returns:
|
||||
* `true` if special
|
||||
*/
|
||||
bool isSpecial() const nothrow @nogc
|
||||
{
|
||||
return isSpecialEnumIdent(ident) && memtype;
|
||||
}
|
||||
|
||||
Expression getDefaultValue(const ref Loc loc)
|
||||
{
|
||||
Expression handleErrors(){
|
||||
defaultval = ErrorExp.get();
|
||||
return defaultval;
|
||||
}
|
||||
//printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars());
|
||||
if (defaultval)
|
||||
return defaultval;
|
||||
|
||||
if (_scope)
|
||||
dsymbolSemantic(this, _scope);
|
||||
if (errors)
|
||||
return handleErrors();
|
||||
if (!members)
|
||||
{
|
||||
if (isSpecial())
|
||||
{
|
||||
/* Allow these special enums to not need a member list
|
||||
*/
|
||||
return defaultval = memtype.defaultInit(loc);
|
||||
}
|
||||
|
||||
error(loc, "is opaque and has no default initializer");
|
||||
return handleErrors();
|
||||
}
|
||||
|
||||
foreach (const i; 0 .. members.dim)
|
||||
{
|
||||
EnumMember em = (*members)[i].isEnumMember();
|
||||
if (em)
|
||||
{
|
||||
if (em.semanticRun < PASS.semanticdone)
|
||||
{
|
||||
error(loc, "forward reference of `%s.init`", toChars());
|
||||
return handleErrors();
|
||||
}
|
||||
|
||||
defaultval = em.value;
|
||||
return defaultval;
|
||||
}
|
||||
}
|
||||
return handleErrors();
|
||||
}
|
||||
|
||||
Type getMemtype(const ref Loc loc)
|
||||
{
|
||||
if (_scope)
|
||||
{
|
||||
/* Enum is forward referenced. We don't need to resolve the whole thing,
|
||||
* just the base type
|
||||
*/
|
||||
if (memtype)
|
||||
{
|
||||
Loc locx = loc.isValid() ? loc : this.loc;
|
||||
memtype = memtype.typeSemantic(locx, _scope);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Run semantic to get the type from a possible first member value
|
||||
dsymbolSemantic(this, _scope);
|
||||
}
|
||||
}
|
||||
if (!memtype)
|
||||
{
|
||||
if (!isAnonymous() && (members || semanticRun >= PASS.semanticdone))
|
||||
memtype = Type.tint32;
|
||||
else
|
||||
{
|
||||
Loc locx = loc.isValid() ? loc : this.loc;
|
||||
error(locx, "is forward referenced looking for base type");
|
||||
return Type.terror;
|
||||
}
|
||||
}
|
||||
return memtype;
|
||||
}
|
||||
|
||||
override inout(EnumDeclaration) isEnumDeclaration() inout
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
Symbol* sinit;
|
||||
|
||||
override void accept(Visitor v)
|
||||
{
|
||||
v.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
* AST node representing a member of an enum.
|
||||
* https://dlang.org/spec/enum.html#EnumMember
|
||||
* https://dlang.org/spec/enum.html#AnonymousEnumMember
|
||||
*/
|
||||
extern (C++) final class EnumMember : VarDeclaration
|
||||
{
|
||||
/* Can take the following forms:
|
||||
* 1. id
|
||||
* 2. id = value
|
||||
* 3. type id = value
|
||||
*/
|
||||
@property ref value() { return (cast(ExpInitializer)_init).exp; }
|
||||
|
||||
// A cast() is injected to 'value' after dsymbolSemantic(),
|
||||
// but 'origValue' will preserve the original value,
|
||||
// or previous value + 1 if none was specified.
|
||||
Expression origValue;
|
||||
|
||||
Type origType;
|
||||
|
||||
EnumDeclaration ed;
|
||||
|
||||
extern (D) this(const ref Loc loc, Identifier id, Expression value, Type origType)
|
||||
{
|
||||
super(loc, null, id ? id : Id.empty, new ExpInitializer(loc, value));
|
||||
this.origValue = value;
|
||||
this.origType = origType;
|
||||
}
|
||||
|
||||
extern(D) this(Loc loc, Identifier id, Expression value, Type memtype,
|
||||
StorageClass stc, UserAttributeDeclaration uad, DeprecatedDeclaration dd)
|
||||
{
|
||||
this(loc, id, value, memtype);
|
||||
storage_class = stc;
|
||||
userAttribDecl = uad;
|
||||
depdecl = dd;
|
||||
}
|
||||
|
||||
override EnumMember syntaxCopy(Dsymbol s)
|
||||
{
|
||||
assert(!s);
|
||||
return new EnumMember(
|
||||
loc, ident,
|
||||
value ? value.syntaxCopy() : null,
|
||||
origType ? origType.syntaxCopy() : null,
|
||||
storage_class,
|
||||
userAttribDecl ? userAttribDecl.syntaxCopy(s) : null,
|
||||
depdecl ? depdecl.syntaxCopy(s) : null);
|
||||
}
|
||||
|
||||
override const(char)* kind() const
|
||||
{
|
||||
return "enum member";
|
||||
}
|
||||
|
||||
override inout(EnumMember) isEnumMember() inout
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
{
|
||||
v.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Check for special enum names.
|
||||
*
|
||||
* Special enum names are used by the C++ name mangler to represent
|
||||
* C++ types that are not basic D types.
|
||||
* Params:
|
||||
* ident = identifier to check for specialness
|
||||
* Returns:
|
||||
* `true` if it is special
|
||||
*/
|
||||
bool isSpecialEnumIdent(const Identifier ident) @nogc nothrow
|
||||
{
|
||||
return ident == Id.__c_long ||
|
||||
ident == Id.__c_ulong ||
|
||||
ident == Id.__c_longlong ||
|
||||
ident == Id.__c_ulonglong ||
|
||||
ident == Id.__c_long_double ||
|
||||
ident == Id.__c_wchar_t ||
|
||||
ident == Id.__c_complex_float ||
|
||||
ident == Id.__c_complex_double ||
|
||||
ident == Id.__c_complex_real;
|
||||
}
|
|
@ -1,320 +0,0 @@
|
|||
|
||||
/* Compiler implementation of the D programming language
|
||||
* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/D-Programming-Language/dmd/blob/master/src/import.c
|
||||
*/
|
||||
|
||||
#include "root/dsystem.h"
|
||||
#include "root/root.h"
|
||||
|
||||
#include "mars.h"
|
||||
#include "dsymbol.h"
|
||||
#include "import.h"
|
||||
#include "identifier.h"
|
||||
#include "module.h"
|
||||
#include "scope.h"
|
||||
#include "mtype.h"
|
||||
#include "declaration.h"
|
||||
#include "id.h"
|
||||
#include "attrib.h"
|
||||
#include "hdrgen.h"
|
||||
|
||||
/********************************* Import ****************************/
|
||||
|
||||
Import::Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId,
|
||||
int isstatic)
|
||||
: Dsymbol(NULL)
|
||||
{
|
||||
assert(id);
|
||||
this->loc = loc;
|
||||
this->packages = packages;
|
||||
this->id = id;
|
||||
this->aliasId = aliasId;
|
||||
this->isstatic = isstatic;
|
||||
this->protection = Prot(Prot::private_); // default to private
|
||||
this->pkg = NULL;
|
||||
this->mod = NULL;
|
||||
|
||||
// Set symbol name (bracketed)
|
||||
if (aliasId)
|
||||
{
|
||||
// import [cstdio] = std.stdio;
|
||||
this->ident = aliasId;
|
||||
}
|
||||
else if (packages && packages->length)
|
||||
{
|
||||
// import [std].stdio;
|
||||
this->ident = (*packages)[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// import [foo];
|
||||
this->ident = id;
|
||||
}
|
||||
}
|
||||
|
||||
void Import::addAlias(Identifier *name, Identifier *alias)
|
||||
{
|
||||
if (isstatic)
|
||||
error("cannot have an import bind list");
|
||||
|
||||
if (!aliasId)
|
||||
this->ident = NULL; // make it an anonymous import
|
||||
|
||||
names.push(name);
|
||||
aliases.push(alias);
|
||||
}
|
||||
|
||||
const char *Import::kind() const
|
||||
{
|
||||
return isstatic ? "static import" : "import";
|
||||
}
|
||||
|
||||
Prot Import::prot()
|
||||
{
|
||||
return protection;
|
||||
}
|
||||
|
||||
Dsymbol *Import::syntaxCopy(Dsymbol *s)
|
||||
{
|
||||
assert(!s);
|
||||
|
||||
Import *si = new Import(loc, packages, id, aliasId, isstatic);
|
||||
|
||||
for (size_t i = 0; i < names.length; i++)
|
||||
{
|
||||
si->addAlias(names[i], aliases[i]);
|
||||
}
|
||||
|
||||
return si;
|
||||
}
|
||||
|
||||
void Import::load(Scope *sc)
|
||||
{
|
||||
//printf("Import::load('%s') %p\n", toPrettyChars(), this);
|
||||
|
||||
// See if existing module
|
||||
DsymbolTable *dst = Package::resolve(packages, NULL, &pkg);
|
||||
Dsymbol *s = dst->lookup(id);
|
||||
if (s)
|
||||
{
|
||||
if (s->isModule())
|
||||
mod = (Module *)s;
|
||||
else
|
||||
{
|
||||
if (s->isAliasDeclaration())
|
||||
{
|
||||
::error(loc, "%s %s conflicts with %s", s->kind(), s->toPrettyChars(), id->toChars());
|
||||
}
|
||||
else if (Package *p = s->isPackage())
|
||||
{
|
||||
if (p->isPkgMod == PKGunknown)
|
||||
{
|
||||
mod = Module::load(loc, packages, id);
|
||||
if (!mod)
|
||||
p->isPkgMod = PKGpackage;
|
||||
else
|
||||
{
|
||||
// mod is a package.d, or a normal module which conflicts with the package name.
|
||||
assert(mod->isPackageFile == (p->isPkgMod == PKGmodule));
|
||||
if (mod->isPackageFile)
|
||||
mod->tag = p->tag; // reuse the same package tag
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mod = p->isPackageMod();
|
||||
}
|
||||
if (!mod)
|
||||
{
|
||||
::error(loc, "can only import from a module, not from package %s.%s",
|
||||
p->toPrettyChars(), id->toChars());
|
||||
}
|
||||
}
|
||||
else if (pkg)
|
||||
{
|
||||
::error(loc, "can only import from a module, not from package %s.%s",
|
||||
pkg->toPrettyChars(), id->toChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
::error(loc, "can only import from a module, not from package %s",
|
||||
id->toChars());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mod)
|
||||
{
|
||||
// Load module
|
||||
mod = Module::load(loc, packages, id);
|
||||
if (mod)
|
||||
{
|
||||
dst->insert(id, mod); // id may be different from mod->ident,
|
||||
// if so then insert alias
|
||||
}
|
||||
}
|
||||
if (mod && !mod->importedFrom)
|
||||
mod->importedFrom = sc ? sc->_module->importedFrom : Module::rootModule;
|
||||
if (!pkg)
|
||||
{
|
||||
if (mod && mod->isPackageFile)
|
||||
{
|
||||
// one level depth package.d file (import pkg; ./pkg/package.d)
|
||||
// it's necessary to use the wrapping Package already created
|
||||
pkg = mod->pkg;
|
||||
}
|
||||
else
|
||||
pkg = mod;
|
||||
}
|
||||
|
||||
//printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg);
|
||||
}
|
||||
|
||||
void Import::importAll(Scope *sc)
|
||||
{
|
||||
if (mod) return; // Already done
|
||||
load(sc);
|
||||
if (!mod) return; // Failed
|
||||
|
||||
if (sc->stc & STCstatic)
|
||||
isstatic = true;
|
||||
mod->importAll(NULL);
|
||||
if (mod->md && mod->md->isdeprecated)
|
||||
{
|
||||
Expression *msg = mod->md->msg;
|
||||
if (StringExp *se = msg ? msg->toStringExp() : NULL)
|
||||
mod->deprecation(loc, "is deprecated - %s", se->string);
|
||||
else
|
||||
mod->deprecation(loc, "is deprecated");
|
||||
}
|
||||
if (sc->explicitProtection)
|
||||
protection = sc->protection;
|
||||
if (!isstatic && !aliasId && !names.length)
|
||||
sc->scopesym->importScope(mod, protection);
|
||||
// Enable access to pkgs/mod as soon as posible, because compiler
|
||||
// can traverse them before the import gets semantic (Issue: 21501)
|
||||
if (!aliasId && !names.length)
|
||||
addPackageAccess(sc->scopesym);
|
||||
}
|
||||
|
||||
/*******************************
|
||||
* Mark the imported packages as accessible from the current
|
||||
* scope. This access check is necessary when using FQN b/c
|
||||
* we're using a single global package tree.
|
||||
* https://issues.dlang.org/show_bug.cgi?id=313
|
||||
*/
|
||||
void Import::addPackageAccess(ScopeDsymbol *scopesym)
|
||||
{
|
||||
//printf("Import::addPackageAccess('%s') %p\n", toPrettyChars(), this);
|
||||
if (packages)
|
||||
{
|
||||
// import a.b.c.d;
|
||||
Package *p = pkg; // a
|
||||
scopesym->addAccessiblePackage(p, protection);
|
||||
for (size_t i = 1; i < packages->length; i++) // [b, c]
|
||||
{
|
||||
Identifier *id = (*packages)[i];
|
||||
p = (Package *) p->symtab->lookup(id);
|
||||
// https://issues.dlang.org/show_bug.cgi?id=17991
|
||||
// An import of truly empty file/package can happen
|
||||
// https://issues.dlang.org/show_bug.cgi?id=20151
|
||||
// Package in the path conflicts with a module name
|
||||
if (p == NULL)
|
||||
return;
|
||||
scopesym->addAccessiblePackage(p, protection);
|
||||
}
|
||||
}
|
||||
scopesym->addAccessiblePackage(mod, protection); // d
|
||||
}
|
||||
|
||||
Dsymbol *Import::toAlias()
|
||||
{
|
||||
if (aliasId)
|
||||
return mod;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*****************************
|
||||
* Add import to sd's symbol table.
|
||||
*/
|
||||
|
||||
void Import::addMember(Scope *sc, ScopeDsymbol *sd)
|
||||
{
|
||||
//printf("Import::addMember(this=%s, sd=%s, sc=%p)\n", toChars(), sd->toChars(), sc);
|
||||
if (names.length == 0)
|
||||
return Dsymbol::addMember(sc, sd);
|
||||
|
||||
if (aliasId)
|
||||
Dsymbol::addMember(sc, sd);
|
||||
|
||||
/* Instead of adding the import to sd's symbol table,
|
||||
* add each of the alias=name pairs
|
||||
*/
|
||||
for (size_t i = 0; i < names.length; i++)
|
||||
{
|
||||
Identifier *name = names[i];
|
||||
Identifier *alias = aliases[i];
|
||||
|
||||
if (!alias)
|
||||
alias = name;
|
||||
|
||||
TypeIdentifier *tname = new TypeIdentifier(loc, name);
|
||||
AliasDeclaration *ad = new AliasDeclaration(loc, alias, tname);
|
||||
ad->_import = this;
|
||||
ad->addMember(sc, sd);
|
||||
|
||||
aliasdecls.push(ad);
|
||||
}
|
||||
}
|
||||
|
||||
void Import::setScope(Scope *sc)
|
||||
{
|
||||
Dsymbol::setScope(sc);
|
||||
if (aliasdecls.length)
|
||||
{
|
||||
if (!mod)
|
||||
importAll(sc);
|
||||
|
||||
sc = sc->push(mod);
|
||||
sc->protection = protection;
|
||||
for (size_t i = 0; i < aliasdecls.length; i++)
|
||||
{
|
||||
AliasDeclaration *ad = aliasdecls[i];
|
||||
ad->setScope(sc);
|
||||
}
|
||||
sc = sc->pop();
|
||||
}
|
||||
}
|
||||
|
||||
Dsymbol *Import::search(const Loc &loc, Identifier *ident, int flags)
|
||||
{
|
||||
//printf("%s.Import::search(ident = '%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
|
||||
|
||||
if (!pkg)
|
||||
{
|
||||
load(NULL);
|
||||
mod->importAll(NULL);
|
||||
dsymbolSemantic(mod, NULL);
|
||||
}
|
||||
|
||||
// Forward it to the package/module
|
||||
return pkg->search(loc, ident, flags);
|
||||
}
|
||||
|
||||
bool Import::overloadInsert(Dsymbol *s)
|
||||
{
|
||||
/* Allow multiple imports with the same package base, but disallow
|
||||
* alias collisions (Bugzilla 5412).
|
||||
*/
|
||||
assert(ident && ident == s->ident);
|
||||
Import *imp;
|
||||
if (!aliasId && (imp = s->isImport()) != NULL && !imp->aliasId)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
358
gcc/d/dmd/dimport.d
Normal file
358
gcc/d/dmd/dimport.d
Normal file
|
@ -0,0 +1,358 @@
|
|||
/**
|
||||
* A `Dsymbol` representing a renamed import.
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dimport.d, _dimport.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_dimport.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dimport.d
|
||||
*/
|
||||
|
||||
module dmd.dimport;
|
||||
|
||||
import dmd.arraytypes;
|
||||
import dmd.astenums;
|
||||
import dmd.declaration;
|
||||
import dmd.dmodule;
|
||||
import dmd.dscope;
|
||||
import dmd.dsymbol;
|
||||
import dmd.dsymbolsem;
|
||||
import dmd.errors;
|
||||
import dmd.expression;
|
||||
import dmd.globals;
|
||||
import dmd.identifier;
|
||||
import dmd.mtype;
|
||||
import dmd.visitor;
|
||||
|
||||
/***********************************************************
|
||||
*/
|
||||
extern (C++) final class Import : Dsymbol
|
||||
{
|
||||
/* static import aliasId = pkg1.pkg2.id : alias1 = name1, alias2 = name2;
|
||||
*/
|
||||
Identifier[] packages; // array of Identifier's representing packages
|
||||
Identifier id; // module Identifier
|
||||
Identifier aliasId;
|
||||
int isstatic; // !=0 if static import
|
||||
Visibility visibility;
|
||||
|
||||
// Pairs of alias=name to bind into current namespace
|
||||
Identifiers names;
|
||||
Identifiers aliases;
|
||||
|
||||
Module mod;
|
||||
Package pkg; // leftmost package/module
|
||||
|
||||
// corresponding AliasDeclarations for alias=name pairs
|
||||
AliasDeclarations aliasdecls;
|
||||
|
||||
extern (D) this(const ref Loc loc, Identifier[] packages, Identifier id, Identifier aliasId, int isstatic)
|
||||
{
|
||||
Identifier selectIdent()
|
||||
{
|
||||
// select Dsymbol identifier (bracketed)
|
||||
if (aliasId)
|
||||
{
|
||||
// import [aliasId] = std.stdio;
|
||||
return aliasId;
|
||||
}
|
||||
else if (packages.length > 0)
|
||||
{
|
||||
// import [std].stdio;
|
||||
return packages[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// import [id];
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
super(loc, selectIdent());
|
||||
|
||||
assert(id);
|
||||
version (none)
|
||||
{
|
||||
printf("Import::Import(");
|
||||
foreach (id; packages)
|
||||
{
|
||||
printf("%s.", id.toChars());
|
||||
}
|
||||
printf("%s)\n", id.toChars());
|
||||
}
|
||||
this.packages = packages;
|
||||
this.id = id;
|
||||
this.aliasId = aliasId;
|
||||
this.isstatic = isstatic;
|
||||
this.visibility = Visibility.Kind.private_; // default to private
|
||||
}
|
||||
|
||||
extern (D) void addAlias(Identifier name, Identifier _alias)
|
||||
{
|
||||
if (isstatic)
|
||||
error("cannot have an import bind list");
|
||||
if (!aliasId)
|
||||
this.ident = null; // make it an anonymous import
|
||||
names.push(name);
|
||||
aliases.push(_alias);
|
||||
}
|
||||
|
||||
override const(char)* kind() const
|
||||
{
|
||||
return isstatic ? "static import" : "import";
|
||||
}
|
||||
|
||||
override Visibility visible() pure nothrow @nogc @safe
|
||||
{
|
||||
return visibility;
|
||||
}
|
||||
|
||||
// copy only syntax trees
|
||||
override Import syntaxCopy(Dsymbol s)
|
||||
{
|
||||
assert(!s);
|
||||
auto si = new Import(loc, packages, id, aliasId, isstatic);
|
||||
si.comment = comment;
|
||||
for (size_t i = 0; i < names.dim; i++)
|
||||
{
|
||||
si.addAlias(names[i], aliases[i]);
|
||||
}
|
||||
return si;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
* Load this module.
|
||||
* Returns:
|
||||
* true for errors, false for success
|
||||
*/
|
||||
bool load(Scope* sc)
|
||||
{
|
||||
//printf("Import::load('%s') %p\n", toPrettyChars(), this);
|
||||
// See if existing module
|
||||
const errors = global.errors;
|
||||
DsymbolTable dst = Package.resolve(packages, null, &pkg);
|
||||
version (none)
|
||||
{
|
||||
if (pkg && pkg.isModule())
|
||||
{
|
||||
.error(loc, "can only import from a module, not from a member of module `%s`. Did you mean `import %s : %s`?", pkg.toChars(), pkg.toPrettyChars(), id.toChars());
|
||||
mod = pkg.isModule(); // Error recovery - treat as import of that module
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Dsymbol s = dst.lookup(id);
|
||||
if (s)
|
||||
{
|
||||
if (s.isModule())
|
||||
mod = cast(Module)s;
|
||||
else
|
||||
{
|
||||
if (s.isAliasDeclaration())
|
||||
{
|
||||
.error(loc, "%s `%s` conflicts with `%s`", s.kind(), s.toPrettyChars(), id.toChars());
|
||||
}
|
||||
else if (Package p = s.isPackage())
|
||||
{
|
||||
if (p.isPkgMod == PKG.unknown)
|
||||
{
|
||||
uint preverrors = global.errors;
|
||||
mod = Module.load(loc, packages, id);
|
||||
if (!mod)
|
||||
p.isPkgMod = PKG.package_;
|
||||
else
|
||||
{
|
||||
// mod is a package.d, or a normal module which conflicts with the package name.
|
||||
if (mod.isPackageFile)
|
||||
mod.tag = p.tag; // reuse the same package tag
|
||||
else
|
||||
{
|
||||
// show error if Module.load does not
|
||||
if (preverrors == global.errors)
|
||||
.error(loc, "%s `%s` from file %s conflicts with %s `%s`", mod.kind(), mod.toPrettyChars(), mod.srcfile.toChars, p.kind(), p.toPrettyChars());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mod = p.isPackageMod();
|
||||
}
|
||||
if (!mod)
|
||||
{
|
||||
.error(loc, "can only import from a module, not from package `%s.%s`", p.toPrettyChars(), id.toChars());
|
||||
}
|
||||
}
|
||||
else if (pkg)
|
||||
{
|
||||
.error(loc, "can only import from a module, not from package `%s.%s`", pkg.toPrettyChars(), id.toChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
.error(loc, "can only import from a module, not from package `%s`", id.toChars());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!mod)
|
||||
{
|
||||
// Load module
|
||||
mod = Module.load(loc, packages, id);
|
||||
if (mod)
|
||||
{
|
||||
// id may be different from mod.ident, if so then insert alias
|
||||
dst.insert(id, mod);
|
||||
}
|
||||
}
|
||||
if (mod && !mod.importedFrom)
|
||||
mod.importedFrom = sc ? sc._module.importedFrom : Module.rootModule;
|
||||
if (!pkg)
|
||||
{
|
||||
if (mod && mod.isPackageFile)
|
||||
{
|
||||
// one level depth package.d file (import pkg; ./pkg/package.d)
|
||||
// it's necessary to use the wrapping Package already created
|
||||
pkg = mod.pkg;
|
||||
}
|
||||
else
|
||||
pkg = mod;
|
||||
}
|
||||
//printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg);
|
||||
return global.errors != errors;
|
||||
}
|
||||
|
||||
override void importAll(Scope* sc)
|
||||
{
|
||||
if (mod) return; // Already done
|
||||
load(sc);
|
||||
if (!mod) return; // Failed
|
||||
|
||||
if (sc.stc & STC.static_)
|
||||
isstatic = true;
|
||||
mod.importAll(null);
|
||||
mod.checkImportDeprecation(loc, sc);
|
||||
if (sc.explicitVisibility)
|
||||
visibility = sc.visibility;
|
||||
if (!isstatic && !aliasId && !names.dim)
|
||||
sc.scopesym.importScope(mod, visibility);
|
||||
// Enable access to pkgs/mod as soon as posible, because compiler
|
||||
// can traverse them before the import gets semantic (Issue: 21501)
|
||||
if (!aliasId && !names.dim)
|
||||
addPackageAccess(sc.scopesym);
|
||||
}
|
||||
|
||||
/*******************************
|
||||
* Mark the imported packages as accessible from the current
|
||||
* scope. This access check is necessary when using FQN b/c
|
||||
* we're using a single global package tree.
|
||||
* https://issues.dlang.org/show_bug.cgi?id=313
|
||||
*/
|
||||
extern (D) void addPackageAccess(ScopeDsymbol scopesym)
|
||||
{
|
||||
//printf("Import::addPackageAccess('%s') %p\n", toPrettyChars(), this);
|
||||
if (packages.length > 0)
|
||||
{
|
||||
// import a.b.c.d;
|
||||
auto p = pkg; // a
|
||||
scopesym.addAccessiblePackage(p, visibility);
|
||||
foreach (id; packages[1 .. $]) // [b, c]
|
||||
{
|
||||
p = cast(Package) p.symtab.lookup(id);
|
||||
// https://issues.dlang.org/show_bug.cgi?id=17991
|
||||
// An import of truly empty file/package can happen
|
||||
// https://issues.dlang.org/show_bug.cgi?id=20151
|
||||
// Package in the path conflicts with a module name
|
||||
if (p is null)
|
||||
break;
|
||||
scopesym.addAccessiblePackage(p, visibility);
|
||||
}
|
||||
}
|
||||
scopesym.addAccessiblePackage(mod, visibility); // d
|
||||
}
|
||||
|
||||
override Dsymbol toAlias()
|
||||
{
|
||||
if (aliasId)
|
||||
return mod;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*****************************
|
||||
* Add import to sd's symbol table.
|
||||
*/
|
||||
override void addMember(Scope* sc, ScopeDsymbol sd)
|
||||
{
|
||||
//printf("Import.addMember(this=%s, sd=%s, sc=%p)\n", toChars(), sd.toChars(), sc);
|
||||
if (names.dim == 0)
|
||||
return Dsymbol.addMember(sc, sd);
|
||||
if (aliasId)
|
||||
Dsymbol.addMember(sc, sd);
|
||||
/* Instead of adding the import to sd's symbol table,
|
||||
* add each of the alias=name pairs
|
||||
*/
|
||||
for (size_t i = 0; i < names.dim; i++)
|
||||
{
|
||||
Identifier name = names[i];
|
||||
Identifier _alias = aliases[i];
|
||||
if (!_alias)
|
||||
_alias = name;
|
||||
auto tname = new TypeIdentifier(loc, name);
|
||||
auto ad = new AliasDeclaration(loc, _alias, tname);
|
||||
ad._import = this;
|
||||
ad.addMember(sc, sd);
|
||||
aliasdecls.push(ad);
|
||||
}
|
||||
}
|
||||
|
||||
override void setScope(Scope* sc)
|
||||
{
|
||||
Dsymbol.setScope(sc);
|
||||
if (aliasdecls.dim)
|
||||
{
|
||||
if (!mod)
|
||||
importAll(sc);
|
||||
|
||||
sc = sc.push(mod);
|
||||
sc.visibility = visibility;
|
||||
foreach (ad; aliasdecls)
|
||||
ad.setScope(sc);
|
||||
sc = sc.pop();
|
||||
}
|
||||
}
|
||||
|
||||
override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
|
||||
{
|
||||
//printf("%s.Import.search(ident = '%s', flags = x%x)\n", toChars(), ident.toChars(), flags);
|
||||
if (!pkg)
|
||||
{
|
||||
load(null);
|
||||
mod.importAll(null);
|
||||
mod.dsymbolSemantic(null);
|
||||
}
|
||||
// Forward it to the package/module
|
||||
return pkg.search(loc, ident, flags);
|
||||
}
|
||||
|
||||
override bool overloadInsert(Dsymbol s)
|
||||
{
|
||||
/* Allow multiple imports with the same package base, but disallow
|
||||
* alias collisions
|
||||
* https://issues.dlang.org/show_bug.cgi?id=5412
|
||||
*/
|
||||
assert(ident && ident == s.ident);
|
||||
Import imp;
|
||||
if (!aliasId && (imp = s.isImport()) !is null && !imp.aliasId)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
override inout(Import) isImport() inout
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
{
|
||||
v.visit(this);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
7487
gcc/d/dmd/dinterpret.d
Normal file
7487
gcc/d/dmd/dinterpret.d
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,458 +0,0 @@
|
|||
|
||||
/* Compiler implementation of the D programming language
|
||||
* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/D-Programming-Language/dmd/blob/master/src/macro.c
|
||||
*/
|
||||
|
||||
/* Simple macro text processor.
|
||||
*/
|
||||
|
||||
#include "root/dsystem.h"
|
||||
|
||||
#include "mars.h"
|
||||
#include "errors.h"
|
||||
#include "root/rmem.h"
|
||||
#include "root/root.h"
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
bool isIdStart(const utf8_t *p);
|
||||
bool isIdTail(const utf8_t *p);
|
||||
int utfStride(const utf8_t *p);
|
||||
|
||||
utf8_t *memdup(const utf8_t *p, size_t len)
|
||||
{
|
||||
return (utf8_t *)memcpy(mem.xmalloc(len), p, len);
|
||||
}
|
||||
|
||||
Macro::Macro(const utf8_t *name, size_t namelen, const utf8_t *text, size_t textlen)
|
||||
{
|
||||
next = NULL;
|
||||
|
||||
this->name = name;
|
||||
this->namelen = namelen;
|
||||
|
||||
this->text = text;
|
||||
this->textlen = textlen;
|
||||
inuse = 0;
|
||||
}
|
||||
|
||||
|
||||
Macro *Macro::search(const utf8_t *name, size_t namelen)
|
||||
{ Macro *table;
|
||||
|
||||
//printf("Macro::search(%.*s)\n", namelen, name);
|
||||
for (table = this; table; table = table->next)
|
||||
{
|
||||
if (table->namelen == namelen &&
|
||||
memcmp(table->name, name, namelen) == 0)
|
||||
{
|
||||
//printf("\tfound %d\n", table->textlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
Macro *Macro::define(Macro **ptable, const utf8_t *name, size_t namelen, const utf8_t *text, size_t textlen)
|
||||
{
|
||||
//printf("Macro::define('%.*s' = '%.*s')\n", namelen, name, textlen, text);
|
||||
|
||||
Macro *table;
|
||||
|
||||
//assert(ptable);
|
||||
for (table = *ptable; table; table = table->next)
|
||||
{
|
||||
if (table->namelen == namelen &&
|
||||
memcmp(table->name, name, namelen) == 0)
|
||||
{
|
||||
table->text = text;
|
||||
table->textlen = textlen;
|
||||
return table;
|
||||
}
|
||||
}
|
||||
table = new Macro(name, namelen, text, textlen);
|
||||
table->next = *ptable;
|
||||
*ptable = table;
|
||||
return table;
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
* Given buffer p[0..end], extract argument marg[0..marglen].
|
||||
* Params:
|
||||
* n 0: get entire argument
|
||||
* 1..9: get nth argument
|
||||
* -1: get 2nd through end
|
||||
*/
|
||||
|
||||
size_t extractArgN(const utf8_t *p, size_t end, const utf8_t **pmarg, size_t *pmarglen, int n)
|
||||
{
|
||||
/* Scan forward for matching right parenthesis.
|
||||
* Nest parentheses.
|
||||
* Skip over "..." and '...' strings inside HTML tags.
|
||||
* Skip over <!-- ... --> comments.
|
||||
* Skip over previous macro insertions
|
||||
* Set marglen.
|
||||
*/
|
||||
unsigned parens = 1;
|
||||
unsigned char instring = 0;
|
||||
unsigned incomment = 0;
|
||||
unsigned intag = 0;
|
||||
unsigned inexp = 0;
|
||||
int argn = 0;
|
||||
|
||||
size_t v = 0;
|
||||
|
||||
Largstart:
|
||||
// Skip first space, if any, to find the start of the macro argument
|
||||
if (n != 1 && v < end && isspace(p[v]))
|
||||
v++;
|
||||
*pmarg = p + v;
|
||||
|
||||
for (; v < end; v++)
|
||||
{ utf8_t c = p[v];
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case ',':
|
||||
if (!inexp && !instring && !incomment && parens == 1)
|
||||
{
|
||||
argn++;
|
||||
if (argn == 1 && n == -1)
|
||||
{ v++;
|
||||
goto Largstart;
|
||||
}
|
||||
if (argn == n)
|
||||
break;
|
||||
if (argn + 1 == n)
|
||||
{ v++;
|
||||
goto Largstart;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
case '(':
|
||||
if (!inexp && !instring && !incomment)
|
||||
parens++;
|
||||
continue;
|
||||
|
||||
case ')':
|
||||
if (!inexp && !instring && !incomment && --parens == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
if (!inexp && !incomment && intag)
|
||||
{
|
||||
if (c == instring)
|
||||
instring = 0;
|
||||
else if (!instring)
|
||||
instring = c;
|
||||
}
|
||||
continue;
|
||||
|
||||
case '<':
|
||||
if (!inexp && !instring && !incomment)
|
||||
{
|
||||
if (v + 6 < end &&
|
||||
p[v + 1] == '!' &&
|
||||
p[v + 2] == '-' &&
|
||||
p[v + 3] == '-')
|
||||
{
|
||||
incomment = 1;
|
||||
v += 3;
|
||||
}
|
||||
else if (v + 2 < end &&
|
||||
isalpha(p[v + 1]))
|
||||
intag = 1;
|
||||
}
|
||||
continue;
|
||||
|
||||
case '>':
|
||||
if (!inexp)
|
||||
intag = 0;
|
||||
continue;
|
||||
|
||||
case '-':
|
||||
if (!inexp &&
|
||||
!instring &&
|
||||
incomment &&
|
||||
v + 2 < end &&
|
||||
p[v + 1] == '-' &&
|
||||
p[v + 2] == '>')
|
||||
{
|
||||
incomment = 0;
|
||||
v += 2;
|
||||
}
|
||||
continue;
|
||||
|
||||
case 0xFF:
|
||||
if (v + 1 < end)
|
||||
{
|
||||
if (p[v + 1] == '{')
|
||||
inexp++;
|
||||
else if (p[v + 1] == '}')
|
||||
inexp--;
|
||||
}
|
||||
continue;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (argn == 0 && n == -1)
|
||||
*pmarg = p + v;
|
||||
*pmarglen = p + v - *pmarg;
|
||||
//printf("extractArg%d('%.*s') = '%.*s'\n", n, end, p, *pmarglen, *pmarg);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
* Expand macro in place in buf.
|
||||
* Only look at the text in buf from start to end.
|
||||
*/
|
||||
|
||||
void Macro::expand(OutBuffer *buf, size_t start, size_t *pend,
|
||||
const utf8_t *arg, size_t arglen)
|
||||
{
|
||||
// limit recursive expansion
|
||||
static int nest;
|
||||
if (nest > global.recursionLimit)
|
||||
{
|
||||
error(Loc(), "DDoc macro expansion limit exceeded; more than %d expansions.",
|
||||
global.recursionLimit);
|
||||
return;
|
||||
}
|
||||
nest++;
|
||||
|
||||
size_t end = *pend;
|
||||
assert(start <= end);
|
||||
assert(end <= buf->length());
|
||||
|
||||
/* First pass - replace $0
|
||||
*/
|
||||
arg = memdup(arg, arglen);
|
||||
for (size_t u = start; u + 1 < end; )
|
||||
{
|
||||
utf8_t *p = (utf8_t *)buf->slice().ptr; // buf->slice().ptr is not loop invariant
|
||||
|
||||
/* Look for $0, but not $$0, and replace it with arg.
|
||||
*/
|
||||
if (p[u] == '$' && (isdigit(p[u + 1]) || p[u + 1] == '+'))
|
||||
{
|
||||
if (u > start && p[u - 1] == '$')
|
||||
{ // Don't expand $$0, but replace it with $0
|
||||
buf->remove(u - 1, 1);
|
||||
end--;
|
||||
u += 1; // now u is one past the closing '1'
|
||||
continue;
|
||||
}
|
||||
|
||||
utf8_t c = p[u + 1];
|
||||
int n = (c == '+') ? -1 : c - '0';
|
||||
|
||||
const utf8_t *marg;
|
||||
size_t marglen;
|
||||
if (n == 0)
|
||||
{
|
||||
marg = arg;
|
||||
marglen = arglen;
|
||||
}
|
||||
else
|
||||
extractArgN(arg, arglen, &marg, &marglen, n);
|
||||
if (marglen == 0)
|
||||
{ // Just remove macro invocation
|
||||
//printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg);
|
||||
buf->remove(u, 2);
|
||||
end -= 2;
|
||||
}
|
||||
else if (c == '+')
|
||||
{
|
||||
// Replace '$+' with 'arg'
|
||||
//printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg);
|
||||
buf->remove(u, 2);
|
||||
buf->insert(u, marg, marglen);
|
||||
end += marglen - 2;
|
||||
|
||||
// Scan replaced text for further expansion
|
||||
size_t mend = u + marglen;
|
||||
expand(buf, u, &mend, NULL, 0);
|
||||
end += mend - (u + marglen);
|
||||
u = mend;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replace '$1' with '\xFF{arg\xFF}'
|
||||
//printf("Replacing '$%c' with '\xFF{%.*s\xFF}'\n", p[u + 1], marglen, marg);
|
||||
buf->slice().ptr[u] = 0xFF;
|
||||
buf->slice().ptr[u + 1] = '{';
|
||||
buf->insert(u + 2, marg, marglen);
|
||||
buf->insert(u + 2 + marglen, (const char *)"\xFF}", 2);
|
||||
end += -2 + 2 + marglen + 2;
|
||||
|
||||
// Scan replaced text for further expansion
|
||||
size_t mend = u + 2 + marglen;
|
||||
expand(buf, u + 2, &mend, NULL, 0);
|
||||
end += mend - (u + 2 + marglen);
|
||||
u = mend;
|
||||
}
|
||||
//printf("u = %d, end = %d\n", u, end);
|
||||
//printf("#%.*s#\n", end, &buf->slice().ptr[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
u++;
|
||||
}
|
||||
|
||||
/* Second pass - replace other macros
|
||||
*/
|
||||
for (size_t u = start; u + 4 < end; )
|
||||
{
|
||||
utf8_t *p = (utf8_t *)buf->slice().ptr; // buf->slice().ptr is not loop invariant
|
||||
|
||||
/* A valid start of macro expansion is $(c, where c is
|
||||
* an id start character, and not $$(c.
|
||||
*/
|
||||
if (p[u] == '$' && p[u + 1] == '(' && isIdStart(p+u+2))
|
||||
{
|
||||
//printf("\tfound macro start '%c'\n", p[u + 2]);
|
||||
utf8_t *name = p + u + 2;
|
||||
size_t namelen = 0;
|
||||
|
||||
const utf8_t *marg;
|
||||
size_t marglen;
|
||||
|
||||
size_t v;
|
||||
/* Scan forward to find end of macro name and
|
||||
* beginning of macro argument (marg).
|
||||
*/
|
||||
for (v = u + 2; v < end; v+=utfStride(p+v))
|
||||
{
|
||||
|
||||
if (!isIdTail(p+v))
|
||||
{ // We've gone past the end of the macro name.
|
||||
namelen = v - (u + 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
v += extractArgN(p + v, end - v, &marg, &marglen, 0);
|
||||
assert(v <= end);
|
||||
|
||||
if (v < end)
|
||||
{ // v is on the closing ')'
|
||||
if (u > start && p[u - 1] == '$')
|
||||
{ // Don't expand $$(NAME), but replace it with $(NAME)
|
||||
buf->remove(u - 1, 1);
|
||||
end--;
|
||||
u = v; // now u is one past the closing ')'
|
||||
continue;
|
||||
}
|
||||
|
||||
Macro *m = search(name, namelen);
|
||||
|
||||
if (!m)
|
||||
{
|
||||
static const char undef[] = "DDOC_UNDEFINED_MACRO";
|
||||
m = search((const utf8_t *)undef, strlen(undef));
|
||||
if (m)
|
||||
{
|
||||
// Macro was not defined, so this is an expansion of
|
||||
// DDOC_UNDEFINED_MACRO. Prepend macro name to args.
|
||||
// marg = name[ ] ~ "," ~ marg[ ];
|
||||
if (marglen)
|
||||
{
|
||||
utf8_t *q = (utf8_t *)mem.xmalloc(namelen + 1 + marglen);
|
||||
assert(q);
|
||||
memcpy(q, name, namelen);
|
||||
q[namelen] = ',';
|
||||
memcpy(q + namelen + 1, marg, marglen);
|
||||
marg = q;
|
||||
marglen += namelen + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
marg = name;
|
||||
marglen = namelen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m)
|
||||
{
|
||||
if (m->inuse && marglen == 0)
|
||||
{ // Remove macro invocation
|
||||
buf->remove(u, v + 1 - u);
|
||||
end -= v + 1 - u;
|
||||
}
|
||||
else if (m->inuse &&
|
||||
((arglen == marglen && memcmp(arg, marg, arglen) == 0) ||
|
||||
(arglen + 4 == marglen &&
|
||||
marg[0] == 0xFF &&
|
||||
marg[1] == '{' &&
|
||||
memcmp(arg, marg + 2, arglen) == 0 &&
|
||||
marg[marglen - 2] == 0xFF &&
|
||||
marg[marglen - 1] == '}'
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
/* Recursive expansion:
|
||||
* marg is same as arg (with blue paint added)
|
||||
* Just leave in place.
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("\tmacro '%.*s'(%.*s) = '%.*s'\n", m->namelen, m->name, marglen, marg, m->textlen, m->text);
|
||||
marg = memdup(marg, marglen);
|
||||
// Insert replacement text
|
||||
buf->spread(v + 1, 2 + m->textlen + 2);
|
||||
buf->slice().ptr[v + 1] = 0xFF;
|
||||
buf->slice().ptr[v + 2] = '{';
|
||||
memcpy(buf->slice().ptr + v + 3, m->text, m->textlen);
|
||||
buf->slice().ptr[v + 3 + m->textlen] = 0xFF;
|
||||
buf->slice().ptr[v + 3 + m->textlen + 1] = '}';
|
||||
|
||||
end += 2 + m->textlen + 2;
|
||||
|
||||
// Scan replaced text for further expansion
|
||||
m->inuse++;
|
||||
size_t mend = v + 1 + 2+m->textlen+2;
|
||||
expand(buf, v + 1, &mend, marg, marglen);
|
||||
end += mend - (v + 1 + 2+m->textlen+2);
|
||||
m->inuse--;
|
||||
|
||||
buf->remove(u, v + 1 - u);
|
||||
end -= v + 1 - u;
|
||||
u += mend - (v + 1);
|
||||
mem.xfree(const_cast<utf8_t *>(marg));
|
||||
//printf("u = %d, end = %d\n", u, end);
|
||||
//printf("#%.*s#\n", end - u, &buf->slice().ptr[u]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replace $(NAME) with nothing
|
||||
buf->remove(u, v + 1 - u);
|
||||
end -= (v + 1 - u);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
u++;
|
||||
}
|
||||
mem.xfree(const_cast<utf8_t *>(arg));
|
||||
*pend = end;
|
||||
nest--;
|
||||
}
|
435
gcc/d/dmd/dmacro.d
Normal file
435
gcc/d/dmd/dmacro.d
Normal file
|
@ -0,0 +1,435 @@
|
|||
/**
|
||||
* Text macro processor for Ddoc.
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmacro.d, _dmacro.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_dmacro.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dmacro.d
|
||||
*/
|
||||
|
||||
module dmd.dmacro;
|
||||
|
||||
import core.stdc.ctype;
|
||||
import core.stdc.string;
|
||||
import dmd.doc;
|
||||
import dmd.errors;
|
||||
import dmd.globals;
|
||||
import dmd.root.outbuffer;
|
||||
import dmd.root.rmem;
|
||||
|
||||
extern (C++) struct MacroTable
|
||||
{
|
||||
/**********************************
|
||||
* Define name=text macro.
|
||||
* If macro `name` already exists, replace the text for it.
|
||||
* Params:
|
||||
* name = name of macro
|
||||
* text = text of macro
|
||||
*/
|
||||
extern (D) void define(const(char)[] name, const(char)[] text)
|
||||
{
|
||||
//printf("MacroTable::define('%.*s' = '%.*s')\n", cast(int)name.length, name.ptr, text.length, text.ptr);
|
||||
Macro* table;
|
||||
for (table = mactab; table; table = table.next)
|
||||
{
|
||||
if (table.name == name)
|
||||
{
|
||||
table.text = text;
|
||||
return;
|
||||
}
|
||||
}
|
||||
table = new Macro(name, text);
|
||||
table.next = mactab;
|
||||
mactab = table;
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
* Look for macros in buf and expand them in place.
|
||||
* Only look at the text in buf from start to pend.
|
||||
*/
|
||||
extern (D) void expand(ref OutBuffer buf, size_t start, ref size_t pend, const(char)[] arg)
|
||||
{
|
||||
version (none)
|
||||
{
|
||||
printf("Macro::expand(buf[%d..%d], arg = '%.*s')\n", start, pend, cast(int)arg.length, arg.ptr);
|
||||
printf("Buf is: '%.*s'\n", cast(int)(pend - start), buf.data + start);
|
||||
}
|
||||
// limit recursive expansion
|
||||
__gshared int nest;
|
||||
if (nest > global.recursionLimit)
|
||||
{
|
||||
error(Loc.initial, "DDoc macro expansion limit exceeded; more than %d expansions.",
|
||||
global.recursionLimit);
|
||||
return;
|
||||
}
|
||||
nest++;
|
||||
size_t end = pend;
|
||||
assert(start <= end);
|
||||
assert(end <= buf.length);
|
||||
/* First pass - replace $0
|
||||
*/
|
||||
arg = memdup(arg);
|
||||
for (size_t u = start; u + 1 < end;)
|
||||
{
|
||||
char* p = cast(char*)buf[].ptr; // buf.data is not loop invariant
|
||||
/* Look for $0, but not $$0, and replace it with arg.
|
||||
*/
|
||||
if (p[u] == '$' && (isdigit(p[u + 1]) || p[u + 1] == '+'))
|
||||
{
|
||||
if (u > start && p[u - 1] == '$')
|
||||
{
|
||||
// Don't expand $$0, but replace it with $0
|
||||
buf.remove(u - 1, 1);
|
||||
end--;
|
||||
u += 1; // now u is one past the closing '1'
|
||||
continue;
|
||||
}
|
||||
char c = p[u + 1];
|
||||
int n = (c == '+') ? -1 : c - '0';
|
||||
const(char)[] marg;
|
||||
if (n == 0)
|
||||
{
|
||||
marg = arg;
|
||||
}
|
||||
else
|
||||
extractArgN(arg, marg, n);
|
||||
if (marg.length == 0)
|
||||
{
|
||||
// Just remove macro invocation
|
||||
//printf("Replacing '$%c' with '%.*s'\n", p[u + 1], cast(int)marg.length, marg.ptr);
|
||||
buf.remove(u, 2);
|
||||
end -= 2;
|
||||
}
|
||||
else if (c == '+')
|
||||
{
|
||||
// Replace '$+' with 'arg'
|
||||
//printf("Replacing '$%c' with '%.*s'\n", p[u + 1], cast(int)marg.length, marg.ptr);
|
||||
buf.remove(u, 2);
|
||||
buf.insert(u, marg);
|
||||
end += marg.length - 2;
|
||||
// Scan replaced text for further expansion
|
||||
size_t mend = u + marg.length;
|
||||
expand(buf, u, mend, null);
|
||||
end += mend - (u + marg.length);
|
||||
u = mend;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replace '$1' with '\xFF{arg\xFF}'
|
||||
//printf("Replacing '$%c' with '\xFF{%.*s\xFF}'\n", p[u + 1], cast(int)marg.length, marg.ptr);
|
||||
ubyte[] slice = cast(ubyte[])buf[];
|
||||
slice[u] = 0xFF;
|
||||
slice[u + 1] = '{';
|
||||
buf.insert(u + 2, marg);
|
||||
buf.insert(u + 2 + marg.length, "\xFF}");
|
||||
end += -2 + 2 + marg.length + 2;
|
||||
// Scan replaced text for further expansion
|
||||
size_t mend = u + 2 + marg.length;
|
||||
expand(buf, u + 2, mend, null);
|
||||
end += mend - (u + 2 + marg.length);
|
||||
u = mend;
|
||||
}
|
||||
//printf("u = %d, end = %d\n", u, end);
|
||||
//printf("#%.*s#\n", cast(int)end, &buf.data[0]);
|
||||
continue;
|
||||
}
|
||||
u++;
|
||||
}
|
||||
/* Second pass - replace other macros
|
||||
*/
|
||||
for (size_t u = start; u + 4 < end;)
|
||||
{
|
||||
char* p = cast(char*)buf[].ptr; // buf.data is not loop invariant
|
||||
/* A valid start of macro expansion is $(c, where c is
|
||||
* an id start character, and not $$(c.
|
||||
*/
|
||||
if (p[u] == '$' && p[u + 1] == '(' && isIdStart(p + u + 2))
|
||||
{
|
||||
//printf("\tfound macro start '%c'\n", p[u + 2]);
|
||||
char* name = p + u + 2;
|
||||
size_t namelen = 0;
|
||||
const(char)[] marg;
|
||||
size_t v;
|
||||
/* Scan forward to find end of macro name and
|
||||
* beginning of macro argument (marg).
|
||||
*/
|
||||
for (v = u + 2; v < end; v += utfStride(p + v))
|
||||
{
|
||||
if (!isIdTail(p + v))
|
||||
{
|
||||
// We've gone past the end of the macro name.
|
||||
namelen = v - (u + 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
v += extractArgN(p[v .. end], marg, 0);
|
||||
assert(v <= end);
|
||||
if (v < end)
|
||||
{
|
||||
// v is on the closing ')'
|
||||
if (u > start && p[u - 1] == '$')
|
||||
{
|
||||
// Don't expand $$(NAME), but replace it with $(NAME)
|
||||
buf.remove(u - 1, 1);
|
||||
end--;
|
||||
u = v; // now u is one past the closing ')'
|
||||
continue;
|
||||
}
|
||||
Macro* m = search(name[0 .. namelen]);
|
||||
if (!m)
|
||||
{
|
||||
immutable undef = "DDOC_UNDEFINED_MACRO";
|
||||
m = search(undef);
|
||||
if (m)
|
||||
{
|
||||
// Macro was not defined, so this is an expansion of
|
||||
// DDOC_UNDEFINED_MACRO. Prepend macro name to args.
|
||||
// marg = name[ ] ~ "," ~ marg[ ];
|
||||
if (marg.length)
|
||||
{
|
||||
char* q = cast(char*)mem.xmalloc(namelen + 1 + marg.length);
|
||||
assert(q);
|
||||
memcpy(q, name, namelen);
|
||||
q[namelen] = ',';
|
||||
memcpy(q + namelen + 1, marg.ptr, marg.length);
|
||||
marg = q[0 .. marg.length + namelen + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
marg = name[0 .. namelen];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m)
|
||||
{
|
||||
if (m.inuse && marg.length == 0)
|
||||
{
|
||||
// Remove macro invocation
|
||||
buf.remove(u, v + 1 - u);
|
||||
end -= v + 1 - u;
|
||||
}
|
||||
else if (m.inuse && ((arg.length == marg.length && memcmp(arg.ptr, marg.ptr, arg.length) == 0) ||
|
||||
(arg.length + 4 == marg.length && marg[0] == 0xFF && marg[1] == '{' && memcmp(arg.ptr, marg.ptr + 2, arg.length) == 0 && marg[marg.length - 2] == 0xFF && marg[marg.length - 1] == '}')))
|
||||
{
|
||||
/* Recursive expansion:
|
||||
* marg is same as arg (with blue paint added)
|
||||
* Just leave in place.
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("\tmacro '%.*s'(%.*s) = '%.*s'\n", cast(int)m.namelen, m.name, cast(int)marg.length, marg.ptr, cast(int)m.textlen, m.text);
|
||||
marg = memdup(marg);
|
||||
// Insert replacement text
|
||||
buf.spread(v + 1, 2 + m.text.length + 2);
|
||||
ubyte[] slice = cast(ubyte[])buf[];
|
||||
slice[v + 1] = 0xFF;
|
||||
slice[v + 2] = '{';
|
||||
slice[v + 3 .. v + 3 + m.text.length] = cast(ubyte[])m.text[];
|
||||
slice[v + 3 + m.text.length] = 0xFF;
|
||||
slice[v + 3 + m.text.length + 1] = '}';
|
||||
end += 2 + m.text.length + 2;
|
||||
// Scan replaced text for further expansion
|
||||
m.inuse++;
|
||||
size_t mend = v + 1 + 2 + m.text.length + 2;
|
||||
expand(buf, v + 1, mend, marg);
|
||||
end += mend - (v + 1 + 2 + m.text.length + 2);
|
||||
m.inuse--;
|
||||
buf.remove(u, v + 1 - u);
|
||||
end -= v + 1 - u;
|
||||
u += mend - (v + 1);
|
||||
mem.xfree(cast(char*)marg.ptr);
|
||||
//printf("u = %d, end = %d\n", u, end);
|
||||
//printf("#%.*s#\n", cast(int)(end - u), &buf.data[u]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replace $(NAME) with nothing
|
||||
buf.remove(u, v + 1 - u);
|
||||
end -= (v + 1 - u);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
u++;
|
||||
}
|
||||
mem.xfree(cast(char*)arg);
|
||||
pend = end;
|
||||
nest--;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
extern (D) Macro* search(const(char)[] name)
|
||||
{
|
||||
Macro* table;
|
||||
//printf("Macro::search(%.*s)\n", cast(int)name.length, name.ptr);
|
||||
for (table = mactab; table; table = table.next)
|
||||
{
|
||||
if (table.name == name)
|
||||
{
|
||||
//printf("\tfound %d\n", table.textlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
Macro* mactab;
|
||||
}
|
||||
|
||||
/* ************************************************************************ */
|
||||
|
||||
private:
|
||||
|
||||
struct Macro
|
||||
{
|
||||
Macro* next; // next in list
|
||||
const(char)[] name; // macro name
|
||||
const(char)[] text; // macro replacement text
|
||||
int inuse; // macro is in use (don't expand)
|
||||
|
||||
this(const(char)[] name, const(char)[] text)
|
||||
{
|
||||
this.name = name;
|
||||
this.text = text;
|
||||
}
|
||||
}
|
||||
|
||||
/************************
|
||||
* Make mutable copy of slice p.
|
||||
* Params:
|
||||
* p = slice
|
||||
* Returns:
|
||||
* copy allocated with mem.xmalloc()
|
||||
*/
|
||||
|
||||
char[] memdup(const(char)[] p)
|
||||
{
|
||||
size_t len = p.length;
|
||||
return (cast(char*)memcpy(mem.xmalloc(len), p.ptr, len))[0 .. len];
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
* Given buffer buf[], extract argument marg[].
|
||||
* Params:
|
||||
* buf = source string
|
||||
* marg = set to slice of buf[]
|
||||
* n = 0: get entire argument
|
||||
* 1..9: get nth argument
|
||||
* -1: get 2nd through end
|
||||
*/
|
||||
size_t extractArgN(const(char)[] buf, out const(char)[] marg, int n)
|
||||
{
|
||||
/* Scan forward for matching right parenthesis.
|
||||
* Nest parentheses.
|
||||
* Skip over "..." and '...' strings inside HTML tags.
|
||||
* Skip over <!-- ... --> comments.
|
||||
* Skip over previous macro insertions
|
||||
* Set marg.
|
||||
*/
|
||||
uint parens = 1;
|
||||
ubyte instring = 0;
|
||||
uint incomment = 0;
|
||||
uint intag = 0;
|
||||
uint inexp = 0;
|
||||
uint argn = 0;
|
||||
size_t v = 0;
|
||||
const p = buf.ptr;
|
||||
const end = buf.length;
|
||||
Largstart:
|
||||
// Skip first space, if any, to find the start of the macro argument
|
||||
if (n != 1 && v < end && isspace(p[v]))
|
||||
v++;
|
||||
size_t vstart = v;
|
||||
for (; v < end; v++)
|
||||
{
|
||||
char c = p[v];
|
||||
switch (c)
|
||||
{
|
||||
case ',':
|
||||
if (!inexp && !instring && !incomment && parens == 1)
|
||||
{
|
||||
argn++;
|
||||
if (argn == 1 && n == -1)
|
||||
{
|
||||
v++;
|
||||
goto Largstart;
|
||||
}
|
||||
if (argn == n)
|
||||
break;
|
||||
if (argn + 1 == n)
|
||||
{
|
||||
v++;
|
||||
goto Largstart;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case '(':
|
||||
if (!inexp && !instring && !incomment)
|
||||
parens++;
|
||||
continue;
|
||||
case ')':
|
||||
if (!inexp && !instring && !incomment && --parens == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
case '"':
|
||||
case '\'':
|
||||
if (!inexp && !incomment && intag)
|
||||
{
|
||||
if (c == instring)
|
||||
instring = 0;
|
||||
else if (!instring)
|
||||
instring = c;
|
||||
}
|
||||
continue;
|
||||
case '<':
|
||||
if (!inexp && !instring && !incomment)
|
||||
{
|
||||
if (v + 6 < end && p[v + 1] == '!' && p[v + 2] == '-' && p[v + 3] == '-')
|
||||
{
|
||||
incomment = 1;
|
||||
v += 3;
|
||||
}
|
||||
else if (v + 2 < end && isalpha(p[v + 1]))
|
||||
intag = 1;
|
||||
}
|
||||
continue;
|
||||
case '>':
|
||||
if (!inexp)
|
||||
intag = 0;
|
||||
continue;
|
||||
case '-':
|
||||
if (!inexp && !instring && incomment && v + 2 < end && p[v + 1] == '-' && p[v + 2] == '>')
|
||||
{
|
||||
incomment = 0;
|
||||
v += 2;
|
||||
}
|
||||
continue;
|
||||
case 0xFF:
|
||||
if (v + 1 < end)
|
||||
{
|
||||
if (p[v + 1] == '{')
|
||||
inexp++;
|
||||
else if (p[v + 1] == '}')
|
||||
inexp--;
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (argn == 0 && n == -1)
|
||||
marg = p[v .. v];
|
||||
else
|
||||
marg = p[vstart .. v];
|
||||
//printf("extractArg%d('%.*s') = '%.*s'\n", n, cast(int)end, p, cast(int)marg.length, marg.ptr);
|
||||
return v;
|
||||
}
|
1122
gcc/d/dmd/dmangle.c
1122
gcc/d/dmd/dmangle.c
File diff suppressed because it is too large
Load diff
1297
gcc/d/dmd/dmangle.d
Normal file
1297
gcc/d/dmd/dmangle.d
Normal file
File diff suppressed because it is too large
Load diff
1276
gcc/d/dmd/dmodule.c
1276
gcc/d/dmd/dmodule.c
File diff suppressed because it is too large
Load diff
1608
gcc/d/dmd/dmodule.d
Normal file
1608
gcc/d/dmd/dmodule.d
Normal file
File diff suppressed because it is too large
Load diff
2807
gcc/d/dmd/doc.c
2807
gcc/d/dmd/doc.c
File diff suppressed because it is too large
Load diff
5388
gcc/d/dmd/doc.d
Normal file
5388
gcc/d/dmd/doc.d
Normal file
File diff suppressed because it is too large
Load diff
|
@ -5,15 +5,11 @@
|
|||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/D-Programming-Language/dmd/blob/master/src/doc.h
|
||||
* https://github.com/dlang/dmd/blob/master/src/dmd/doc.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "root/dsystem.h"
|
||||
|
||||
class Module;
|
||||
struct OutBuffer;
|
||||
|
||||
void escapeDdocString(OutBuffer *buf, size_t start);
|
||||
void gendocfile(Module *m);
|
||||
|
|
|
@ -1,646 +0,0 @@
|
|||
|
||||
/* Compiler implementation of the D programming language
|
||||
* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/D-Programming-Language/dmd/blob/master/src/scope.c
|
||||
*/
|
||||
|
||||
#include "root/dsystem.h" // strlen()
|
||||
#include "root/root.h"
|
||||
#include "root/rmem.h"
|
||||
#include "root/speller.h"
|
||||
|
||||
#include "mars.h"
|
||||
#include "init.h"
|
||||
#include "identifier.h"
|
||||
#include "scope.h"
|
||||
#include "attrib.h"
|
||||
#include "dsymbol.h"
|
||||
#include "declaration.h"
|
||||
#include "statement.h"
|
||||
#include "aggregate.h"
|
||||
#include "module.h"
|
||||
#include "id.h"
|
||||
#include "target.h"
|
||||
#include "template.h"
|
||||
|
||||
Scope *Scope::freelist = NULL;
|
||||
|
||||
void allocFieldinit(Scope *sc, size_t dim)
|
||||
{
|
||||
sc->fieldinit = (unsigned *)mem.xcalloc(sizeof(unsigned), dim);
|
||||
sc->fieldinit_dim = dim;
|
||||
}
|
||||
|
||||
void freeFieldinit(Scope *sc)
|
||||
{
|
||||
if (sc->fieldinit)
|
||||
mem.xfree(sc->fieldinit);
|
||||
sc->fieldinit = NULL;
|
||||
sc->fieldinit_dim = 0;
|
||||
}
|
||||
|
||||
Scope *Scope::alloc()
|
||||
{
|
||||
if (freelist)
|
||||
{
|
||||
Scope *s = freelist;
|
||||
freelist = s->enclosing;
|
||||
//printf("freelist %p\n", s);
|
||||
assert(s->flags & SCOPEfree);
|
||||
s->flags &= ~SCOPEfree;
|
||||
return s;
|
||||
}
|
||||
|
||||
return new Scope();
|
||||
}
|
||||
|
||||
Scope::Scope()
|
||||
{
|
||||
// Create root scope
|
||||
|
||||
//printf("Scope::Scope() %p\n", this);
|
||||
this->_module = NULL;
|
||||
this->scopesym = NULL;
|
||||
this->enclosing = NULL;
|
||||
this->parent = NULL;
|
||||
this->sw = NULL;
|
||||
this->tf = NULL;
|
||||
this->os = NULL;
|
||||
this->tinst = NULL;
|
||||
this->minst = NULL;
|
||||
this->sbreak = NULL;
|
||||
this->scontinue = NULL;
|
||||
this->fes = NULL;
|
||||
this->callsc = NULL;
|
||||
this->aligndecl = NULL;
|
||||
this->func = NULL;
|
||||
this->slabel = NULL;
|
||||
this->linkage = LINKd;
|
||||
this->cppmangle = CPPMANGLEdefault;
|
||||
this->inlining = PINLINEdefault;
|
||||
this->protection = Prot(Prot::public_);
|
||||
this->explicitProtection = 0;
|
||||
this->stc = 0;
|
||||
this->depdecl = NULL;
|
||||
this->inunion = 0;
|
||||
this->nofree = 0;
|
||||
this->noctor = 0;
|
||||
this->intypeof = 0;
|
||||
this->lastVar = NULL;
|
||||
this->callSuper = 0;
|
||||
this->fieldinit = NULL;
|
||||
this->fieldinit_dim = 0;
|
||||
this->flags = 0;
|
||||
this->lastdc = NULL;
|
||||
this->anchorCounts = NULL;
|
||||
this->prevAnchor = NULL;
|
||||
this->userAttribDecl = NULL;
|
||||
}
|
||||
|
||||
Scope *Scope::copy()
|
||||
{
|
||||
Scope *sc = Scope::alloc();
|
||||
*sc = *this; // memcpy
|
||||
|
||||
/* Bugzilla 11777: The copied scope should not inherit fieldinit.
|
||||
*/
|
||||
sc->fieldinit = NULL;
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
Scope *Scope::createGlobal(Module *_module)
|
||||
{
|
||||
Scope *sc = Scope::alloc();
|
||||
*sc = Scope(); // memset
|
||||
|
||||
sc->aligndecl = NULL;
|
||||
sc->linkage = LINKd;
|
||||
sc->inlining = PINLINEdefault;
|
||||
sc->protection = Prot(Prot::public_);
|
||||
|
||||
sc->_module = _module;
|
||||
|
||||
sc->tinst = NULL;
|
||||
sc->minst = _module;
|
||||
|
||||
sc->scopesym = new ScopeDsymbol();
|
||||
sc->scopesym->symtab = new DsymbolTable();
|
||||
|
||||
// Add top level package as member of this global scope
|
||||
Dsymbol *m = _module;
|
||||
while (m->parent)
|
||||
m = m->parent;
|
||||
m->addMember(NULL, sc->scopesym);
|
||||
m->parent = NULL; // got changed by addMember()
|
||||
|
||||
// Create the module scope underneath the global scope
|
||||
sc = sc->push(_module);
|
||||
sc->parent = _module;
|
||||
return sc;
|
||||
}
|
||||
|
||||
Scope *Scope::push()
|
||||
{
|
||||
Scope *s = copy();
|
||||
|
||||
//printf("Scope::push(this = %p) new = %p\n", this, s);
|
||||
assert(!(flags & SCOPEfree));
|
||||
s->scopesym = NULL;
|
||||
s->enclosing = this;
|
||||
s->slabel = NULL;
|
||||
s->nofree = 0;
|
||||
s->fieldinit = saveFieldInit();
|
||||
s->flags = (flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe | SCOPEcompile | SCOPEconstraint |
|
||||
SCOPEnoaccesscheck | SCOPEignoresymbolvisibility |
|
||||
SCOPEprintf | SCOPEscanf));
|
||||
s->lastdc = NULL;
|
||||
|
||||
assert(this != s);
|
||||
return s;
|
||||
}
|
||||
|
||||
Scope *Scope::push(ScopeDsymbol *ss)
|
||||
{
|
||||
//printf("Scope::push(%s)\n", ss->toChars());
|
||||
Scope *s = push();
|
||||
s->scopesym = ss;
|
||||
return s;
|
||||
}
|
||||
|
||||
Scope *Scope::pop()
|
||||
{
|
||||
//printf("Scope::pop() %p nofree = %d\n", this, nofree);
|
||||
Scope *enc = enclosing;
|
||||
|
||||
if (enclosing)
|
||||
{
|
||||
enclosing->callSuper |= callSuper;
|
||||
if (fieldinit)
|
||||
{
|
||||
if (enclosing->fieldinit)
|
||||
{
|
||||
assert(fieldinit != enclosing->fieldinit);
|
||||
size_t dim = fieldinit_dim;
|
||||
for (size_t i = 0; i < dim; i++)
|
||||
enclosing->fieldinit[i] |= fieldinit[i];
|
||||
}
|
||||
freeFieldinit(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (!nofree)
|
||||
{
|
||||
enclosing = freelist;
|
||||
freelist = this;
|
||||
flags |= SCOPEfree;
|
||||
}
|
||||
|
||||
return enc;
|
||||
}
|
||||
|
||||
Scope *Scope::startCTFE()
|
||||
{
|
||||
Scope *sc = this->push();
|
||||
sc->flags = this->flags | SCOPEctfe;
|
||||
return sc;
|
||||
}
|
||||
|
||||
Scope *Scope::endCTFE()
|
||||
{
|
||||
assert(flags & SCOPEctfe);
|
||||
return pop();
|
||||
}
|
||||
|
||||
void Scope::mergeCallSuper(Loc loc, unsigned cs)
|
||||
{
|
||||
// This does a primitive flow analysis to support the restrictions
|
||||
// regarding when and how constructors can appear.
|
||||
// It merges the results of two paths.
|
||||
// The two paths are callSuper and cs; the result is merged into callSuper.
|
||||
|
||||
if (cs != callSuper)
|
||||
{
|
||||
// Have ALL branches called a constructor?
|
||||
int aAll = (cs & (CSXthis_ctor | CSXsuper_ctor)) != 0;
|
||||
int bAll = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0;
|
||||
|
||||
// Have ANY branches called a constructor?
|
||||
bool aAny = (cs & CSXany_ctor) != 0;
|
||||
bool bAny = (callSuper & CSXany_ctor) != 0;
|
||||
|
||||
// Have any branches returned?
|
||||
bool aRet = (cs & CSXreturn) != 0;
|
||||
bool bRet = (callSuper & CSXreturn) != 0;
|
||||
|
||||
// Have any branches halted?
|
||||
bool aHalt = (cs & CSXhalt) != 0;
|
||||
bool bHalt = (callSuper & CSXhalt) != 0;
|
||||
|
||||
bool ok = true;
|
||||
|
||||
if (aHalt && bHalt)
|
||||
{
|
||||
callSuper = CSXhalt;
|
||||
}
|
||||
else if ((!aHalt && aRet && !aAny && bAny) ||
|
||||
(!bHalt && bRet && !bAny && aAny))
|
||||
{
|
||||
// If one has returned without a constructor call, there must be never
|
||||
// have been ctor calls in the other.
|
||||
ok = false;
|
||||
}
|
||||
else if (aHalt || (aRet && aAll))
|
||||
{
|
||||
// If one branch has called a ctor and then exited, anything the
|
||||
// other branch has done is OK (except returning without a
|
||||
// ctor call, but we already checked that).
|
||||
callSuper |= cs & (CSXany_ctor | CSXlabel);
|
||||
}
|
||||
else if (bHalt || (bRet && bAll))
|
||||
{
|
||||
callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Both branches must have called ctors, or both not.
|
||||
ok = (aAll == bAll);
|
||||
// If one returned without a ctor, we must remember that
|
||||
// (Don't bother if we've already found an error)
|
||||
if (ok && aRet && !aAny)
|
||||
callSuper |= CSXreturn;
|
||||
callSuper |= cs & (CSXany_ctor | CSXlabel);
|
||||
}
|
||||
if (!ok)
|
||||
error(loc, "one path skips constructor");
|
||||
}
|
||||
}
|
||||
|
||||
unsigned *Scope::saveFieldInit()
|
||||
{
|
||||
unsigned *fi = NULL;
|
||||
if (fieldinit) // copy
|
||||
{
|
||||
size_t dim = fieldinit_dim;
|
||||
fi = (unsigned *)mem.xmalloc(sizeof(unsigned) * dim);
|
||||
for (size_t i = 0; i < dim; i++)
|
||||
fi[i] = fieldinit[i];
|
||||
}
|
||||
return fi;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Merge `b` flow analysis results into `a`.
|
||||
* Params:
|
||||
* a = the path to merge fi into
|
||||
* b = the other path
|
||||
* Returns:
|
||||
* false means either `a` or `b` skips initialization
|
||||
*/
|
||||
static bool mergeFieldInit(unsigned &a, const unsigned b)
|
||||
{
|
||||
if (b == a)
|
||||
return true;
|
||||
|
||||
// Have any branches returned?
|
||||
bool aRet = (a & CSXreturn) != 0;
|
||||
bool bRet = (b & CSXreturn) != 0;
|
||||
|
||||
// Have any branches halted?
|
||||
bool aHalt = (a & CSXhalt) != 0;
|
||||
bool bHalt = (b & CSXhalt) != 0;
|
||||
|
||||
if (aHalt && bHalt)
|
||||
{
|
||||
a = CSXhalt;
|
||||
return true;
|
||||
}
|
||||
|
||||
// The logic here is to prefer the branch that neither halts nor returns.
|
||||
bool ok;
|
||||
if (!bHalt && bRet)
|
||||
{
|
||||
// Branch b returns, no merging required.
|
||||
ok = (b & CSXthis_ctor);
|
||||
}
|
||||
else if (!aHalt && aRet)
|
||||
{
|
||||
// Branch a returns, but b doesn't, b takes precedence.
|
||||
ok = (a & CSXthis_ctor);
|
||||
a = b;
|
||||
}
|
||||
else if (bHalt)
|
||||
{
|
||||
// Branch b halts, no merging required.
|
||||
ok = (a & CSXthis_ctor);
|
||||
}
|
||||
else if (aHalt)
|
||||
{
|
||||
// Branch a halts, but b doesn't, b takes precedence
|
||||
ok = (b & CSXthis_ctor);
|
||||
a = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Neither branch returns nor halts, merge flags
|
||||
ok = !((a ^ b) & CSXthis_ctor);
|
||||
a |= b;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void Scope::mergeFieldInit(Loc loc, unsigned *fies)
|
||||
{
|
||||
if (fieldinit && fies)
|
||||
{
|
||||
FuncDeclaration *f = func;
|
||||
if (fes) f = fes->func;
|
||||
AggregateDeclaration *ad = f->isMember2();
|
||||
assert(ad);
|
||||
|
||||
for (size_t i = 0; i < ad->fields.length; i++)
|
||||
{
|
||||
VarDeclaration *v = ad->fields[i];
|
||||
bool mustInit = (v->storage_class & STCnodefaultctor ||
|
||||
v->type->needsNested());
|
||||
|
||||
if (!::mergeFieldInit(fieldinit[i], fies[i]) && mustInit)
|
||||
{
|
||||
::error(loc, "one path skips field %s", v->toChars());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Module *Scope::instantiatingModule()
|
||||
{
|
||||
// TODO: in speculative context, returning 'module' is correct?
|
||||
return minst ? minst : _module;
|
||||
}
|
||||
|
||||
static Dsymbol *searchScopes(Scope *scope, Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags)
|
||||
{
|
||||
for (Scope *sc = scope; sc; sc = sc->enclosing)
|
||||
{
|
||||
assert(sc != sc->enclosing);
|
||||
if (!sc->scopesym)
|
||||
continue;
|
||||
//printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc->scopesym->toChars(), sc->scopesym->kind(), flags);
|
||||
|
||||
if (sc->scopesym->isModule())
|
||||
flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
|
||||
|
||||
if (Dsymbol *s = sc->scopesym->search(loc, ident, flags))
|
||||
{
|
||||
if (!(flags & (SearchImportsOnly | IgnoreErrors)) &&
|
||||
ident == Id::length && sc->scopesym->isArrayScopeSymbol() &&
|
||||
sc->enclosing && sc->enclosing->search(loc, ident, NULL, flags))
|
||||
{
|
||||
warning(s->loc, "array `length` hides other `length` name in outer scope");
|
||||
}
|
||||
if (pscopesym)
|
||||
*pscopesym = sc->scopesym;
|
||||
return s;
|
||||
}
|
||||
// Stop when we hit a module, but keep going if that is not just under the global scope
|
||||
if (sc->scopesym->isModule() && !(sc->enclosing && !sc->enclosing->enclosing))
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/************************************
|
||||
* Perform unqualified name lookup by following the chain of scopes up
|
||||
* until found.
|
||||
*
|
||||
* Params:
|
||||
* loc = location to use for error messages
|
||||
* ident = name to look up
|
||||
* pscopesym = if supplied and name is found, set to scope that ident was found in
|
||||
* flags = modify search based on flags
|
||||
*
|
||||
* Returns:
|
||||
* symbol if found, null if not
|
||||
*/
|
||||
Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags)
|
||||
{
|
||||
// This function is called only for unqualified lookup
|
||||
assert(!(flags & (SearchLocalsOnly | SearchImportsOnly)));
|
||||
|
||||
/* If ident is "start at module scope", only look at module scope
|
||||
*/
|
||||
if (ident == Id::empty)
|
||||
{
|
||||
// Look for module scope
|
||||
for (Scope *sc = this; sc; sc = sc->enclosing)
|
||||
{
|
||||
assert(sc != sc->enclosing);
|
||||
if (!sc->scopesym)
|
||||
continue;
|
||||
|
||||
if (Dsymbol *s = sc->scopesym->isModule())
|
||||
{
|
||||
if (pscopesym)
|
||||
*pscopesym = sc->scopesym;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (this->flags & SCOPEignoresymbolvisibility)
|
||||
flags |= IgnoreSymbolVisibility;
|
||||
|
||||
// First look in local scopes
|
||||
Dsymbol *s = searchScopes(this, loc, ident, pscopesym, flags | SearchLocalsOnly);
|
||||
if (!s)
|
||||
{
|
||||
// Second look in imported modules
|
||||
s = searchScopes(this, loc, ident, pscopesym, flags | SearchImportsOnly);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
Dsymbol *Scope::insert(Dsymbol *s)
|
||||
{
|
||||
if (VarDeclaration *vd = s->isVarDeclaration())
|
||||
{
|
||||
if (lastVar)
|
||||
vd->lastVar = lastVar;
|
||||
lastVar = vd;
|
||||
}
|
||||
else if (WithScopeSymbol *ss = s->isWithScopeSymbol())
|
||||
{
|
||||
if (VarDeclaration *wthis = ss->withstate->wthis)
|
||||
{
|
||||
if (lastVar)
|
||||
wthis->lastVar = lastVar;
|
||||
lastVar = wthis;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
for (Scope *sc = this; sc; sc = sc->enclosing)
|
||||
{
|
||||
//printf("\tsc = %p\n", sc);
|
||||
if (sc->scopesym)
|
||||
{
|
||||
//printf("\t\tsc->scopesym = %p\n", sc->scopesym);
|
||||
if (!sc->scopesym->symtab)
|
||||
sc->scopesym->symtab = new DsymbolTable();
|
||||
return sc->scopesym->symtabInsert(s);
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* Search enclosing scopes for ClassDeclaration.
|
||||
*/
|
||||
|
||||
ClassDeclaration *Scope::getClassScope()
|
||||
{
|
||||
for (Scope *sc = this; sc; sc = sc->enclosing)
|
||||
{
|
||||
if (!sc->scopesym)
|
||||
continue;
|
||||
|
||||
ClassDeclaration *cd = sc->scopesym->isClassDeclaration();
|
||||
if (cd)
|
||||
return cd;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* Search enclosing scopes for ClassDeclaration.
|
||||
*/
|
||||
|
||||
AggregateDeclaration *Scope::getStructClassScope()
|
||||
{
|
||||
for (Scope *sc = this; sc; sc = sc->enclosing)
|
||||
{
|
||||
if (!sc->scopesym)
|
||||
continue;
|
||||
|
||||
AggregateDeclaration *ad = sc->scopesym->isClassDeclaration();
|
||||
if (ad)
|
||||
return ad;
|
||||
ad = sc->scopesym->isStructDeclaration();
|
||||
if (ad)
|
||||
return ad;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
* For TemplateDeclarations, we need to remember the Scope
|
||||
* where it was declared. So mark the Scope as not
|
||||
* to be free'd.
|
||||
*/
|
||||
|
||||
void Scope::setNoFree()
|
||||
{
|
||||
//int i = 0;
|
||||
|
||||
//printf("Scope::setNoFree(this = %p)\n", this);
|
||||
for (Scope *sc = this; sc; sc = sc->enclosing)
|
||||
{
|
||||
//printf("\tsc = %p\n", sc);
|
||||
sc->nofree = 1;
|
||||
|
||||
assert(!(flags & SCOPEfree));
|
||||
//assert(sc != sc->enclosing);
|
||||
//assert(!sc->enclosing || sc != sc->enclosing->enclosing);
|
||||
//if (++i == 10)
|
||||
//assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
structalign_t Scope::alignment()
|
||||
{
|
||||
if (aligndecl)
|
||||
return aligndecl->getAlignment(this);
|
||||
else
|
||||
return STRUCTALIGN_DEFAULT;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Given the failed search attempt, try to find
|
||||
* one with a close spelling.
|
||||
*/
|
||||
|
||||
static void *scope_search_fp(void *arg, const char *seed, int* cost)
|
||||
{
|
||||
//printf("scope_search_fp('%s')\n", seed);
|
||||
|
||||
/* If not in the lexer's string table, it certainly isn't in the symbol table.
|
||||
* Doing this first is a lot faster.
|
||||
*/
|
||||
size_t len = strlen(seed);
|
||||
if (!len)
|
||||
return NULL;
|
||||
Identifier *id = Identifier::lookup(seed, len);
|
||||
if (!id)
|
||||
return NULL;
|
||||
|
||||
Scope *sc = (Scope *)arg;
|
||||
Module::clearCache();
|
||||
Dsymbol *scopesym = NULL;
|
||||
Dsymbol *s = sc->search(Loc(), id, &scopesym, IgnoreErrors);
|
||||
if (s)
|
||||
{
|
||||
for (*cost = 0; sc; sc = sc->enclosing, (*cost)++)
|
||||
if (sc->scopesym == scopesym)
|
||||
break;
|
||||
if (scopesym != s->parent)
|
||||
{
|
||||
(*cost)++; // got to the symbol through an import
|
||||
if (s->prot().kind == Prot::private_)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return (void*)s;
|
||||
}
|
||||
|
||||
Dsymbol *Scope::search_correct(Identifier *ident)
|
||||
{
|
||||
if (global.gag)
|
||||
return NULL; // don't do it for speculative compiles; too time consuming
|
||||
|
||||
Dsymbol *scopesym = NULL;
|
||||
// search for exact name first
|
||||
if (Dsymbol *s = search(Loc(), ident, &scopesym, IgnoreErrors))
|
||||
return s;
|
||||
return (Dsymbol *)speller(ident->toChars(), &scope_search_fp, this, idchars);
|
||||
}
|
||||
|
||||
/************************************
|
||||
* Maybe `ident` was a C or C++ name. Check for that,
|
||||
* and suggest the D equivalent.
|
||||
* Params:
|
||||
* ident = unknown identifier
|
||||
* Returns:
|
||||
* D identifier string if found, null if not
|
||||
*/
|
||||
const char *Scope::search_correct_C(Identifier *ident)
|
||||
{
|
||||
TOK tok;
|
||||
if (ident == Id::C_NULL)
|
||||
tok = TOKnull;
|
||||
else if (ident == Id::C_TRUE)
|
||||
tok = TOKtrue;
|
||||
else if (ident == Id::C_FALSE)
|
||||
tok = TOKfalse;
|
||||
else if (ident == Id::C_unsigned)
|
||||
tok = TOKuns32;
|
||||
else if (ident == Id::C_wchar_t)
|
||||
tok = target.c.twchar_t->ty == Twchar ? TOKwchar : TOKdchar;
|
||||
else
|
||||
return NULL;
|
||||
return Token::toChars(tok);
|
||||
}
|
768
gcc/d/dmd/dscope.d
Normal file
768
gcc/d/dmd/dscope.d
Normal file
|
@ -0,0 +1,768 @@
|
|||
/**
|
||||
* A scope as defined by curly braces `{}`.
|
||||
*
|
||||
* Not to be confused with the `scope` storage class.
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
||||
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dscope.d, _dscope.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_dscope.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dscope.d
|
||||
*/
|
||||
|
||||
module dmd.dscope;
|
||||
|
||||
import core.stdc.stdio;
|
||||
import core.stdc.string;
|
||||
import dmd.aggregate;
|
||||
import dmd.arraytypes;
|
||||
import dmd.astenums;
|
||||
import dmd.attrib;
|
||||
import dmd.ctorflow;
|
||||
import dmd.dclass;
|
||||
import dmd.declaration;
|
||||
import dmd.dmodule;
|
||||
import dmd.doc;
|
||||
import dmd.dsymbol;
|
||||
import dmd.dsymbolsem;
|
||||
import dmd.dtemplate;
|
||||
import dmd.expression;
|
||||
import dmd.errors;
|
||||
import dmd.func;
|
||||
import dmd.globals;
|
||||
import dmd.id;
|
||||
import dmd.identifier;
|
||||
import dmd.root.outbuffer;
|
||||
import dmd.root.rmem;
|
||||
import dmd.root.speller;
|
||||
import dmd.statement;
|
||||
import dmd.target;
|
||||
import dmd.tokens;
|
||||
|
||||
//version=LOGSEARCH;
|
||||
|
||||
|
||||
// List of flags that can be applied to this `Scope`
|
||||
enum SCOPE
|
||||
{
|
||||
ctor = 0x0001, /// constructor type
|
||||
noaccesscheck = 0x0002, /// don't do access checks
|
||||
condition = 0x0004, /// inside static if/assert condition
|
||||
debug_ = 0x0008, /// inside debug conditional
|
||||
constraint = 0x0010, /// inside template constraint
|
||||
invariant_ = 0x0020, /// inside invariant code
|
||||
require = 0x0040, /// inside in contract code
|
||||
ensure = 0x0060, /// inside out contract code
|
||||
contract = 0x0060, /// [mask] we're inside contract code
|
||||
ctfe = 0x0080, /// inside a ctfe-only expression
|
||||
compile = 0x0100, /// inside __traits(compile)
|
||||
ignoresymbolvisibility = 0x0200, /// ignore symbol visibility
|
||||
/// https://issues.dlang.org/show_bug.cgi?id=15907
|
||||
onlysafeaccess = 0x0400, /// unsafe access is not allowed for @safe code
|
||||
Cfile = 0x0800, /// C semantics apply
|
||||
free = 0x8000, /// is on free list
|
||||
|
||||
fullinst = 0x10000, /// fully instantiate templates
|
||||
alias_ = 0x20000, /// inside alias declaration.
|
||||
|
||||
// The following are mutually exclusive
|
||||
printf = 0x4_0000, /// printf-style function
|
||||
scanf = 0x8_0000, /// scanf-style function
|
||||
}
|
||||
|
||||
/// Flags that are carried along with a scope push()
|
||||
private enum PersistentFlags =
|
||||
SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint |
|
||||
SCOPE.noaccesscheck | SCOPE.onlysafeaccess | SCOPE.ignoresymbolvisibility |
|
||||
SCOPE.printf | SCOPE.scanf | SCOPE.Cfile;
|
||||
|
||||
struct Scope
|
||||
{
|
||||
Scope* enclosing; /// enclosing Scope
|
||||
|
||||
Module _module; /// Root module
|
||||
ScopeDsymbol scopesym; /// current symbol
|
||||
FuncDeclaration func; /// function we are in
|
||||
Dsymbol parent; /// parent to use
|
||||
LabelStatement slabel; /// enclosing labelled statement
|
||||
SwitchStatement sw; /// enclosing switch statement
|
||||
Statement tryBody; /// enclosing _body of TryCatchStatement or TryFinallyStatement
|
||||
TryFinallyStatement tf; /// enclosing try finally statement
|
||||
ScopeGuardStatement os; /// enclosing scope(xxx) statement
|
||||
Statement sbreak; /// enclosing statement that supports "break"
|
||||
Statement scontinue; /// enclosing statement that supports "continue"
|
||||
ForeachStatement fes; /// if nested function for ForeachStatement, this is it
|
||||
Scope* callsc; /// used for __FUNCTION__, __PRETTY_FUNCTION__ and __MODULE__
|
||||
Dsymbol inunion; /// != null if processing members of a union
|
||||
bool nofree; /// true if shouldn't free it
|
||||
bool inLoop; /// true if inside a loop (where constructor calls aren't allowed)
|
||||
int intypeof; /// in typeof(exp)
|
||||
VarDeclaration lastVar; /// Previous symbol used to prevent goto-skips-init
|
||||
|
||||
/* If minst && !tinst, it's in definitely non-speculative scope (eg. module member scope).
|
||||
* If !minst && !tinst, it's in definitely speculative scope (eg. template constraint).
|
||||
* If minst && tinst, it's in instantiated code scope without speculation.
|
||||
* If !minst && tinst, it's in instantiated code scope with speculation.
|
||||
*/
|
||||
Module minst; /// root module where the instantiated templates should belong to
|
||||
TemplateInstance tinst; /// enclosing template instance
|
||||
|
||||
CtorFlow ctorflow; /// flow analysis for constructors
|
||||
|
||||
/// alignment for struct members
|
||||
AlignDeclaration aligndecl;
|
||||
|
||||
/// C++ namespace this symbol is in
|
||||
CPPNamespaceDeclaration namespace;
|
||||
|
||||
/// linkage for external functions
|
||||
LINK linkage = LINK.d;
|
||||
|
||||
/// mangle type
|
||||
CPPMANGLE cppmangle = CPPMANGLE.def;
|
||||
|
||||
/// inlining strategy for functions
|
||||
PragmaDeclaration inlining;
|
||||
|
||||
/// visibility for class members
|
||||
Visibility visibility = Visibility(Visibility.Kind.public_);
|
||||
int explicitVisibility; /// set if in an explicit visibility attribute
|
||||
|
||||
StorageClass stc; /// storage class
|
||||
|
||||
DeprecatedDeclaration depdecl; /// customized deprecation message
|
||||
|
||||
uint flags;
|
||||
|
||||
// user defined attributes
|
||||
UserAttributeDeclaration userAttribDecl;
|
||||
|
||||
DocComment* lastdc; /// documentation comment for last symbol at this scope
|
||||
uint[void*] anchorCounts; /// lookup duplicate anchor name count
|
||||
Identifier prevAnchor; /// qualified symbol name of last doc anchor
|
||||
|
||||
AliasDeclaration aliasAsg; /// if set, then aliasAsg is being assigned a new value,
|
||||
/// do not set wasRead for it
|
||||
|
||||
extern (D) __gshared Scope* freelist;
|
||||
|
||||
extern (D) static Scope* alloc()
|
||||
{
|
||||
if (freelist)
|
||||
{
|
||||
Scope* s = freelist;
|
||||
freelist = s.enclosing;
|
||||
//printf("freelist %p\n", s);
|
||||
assert(s.flags & SCOPE.free);
|
||||
s.flags &= ~SCOPE.free;
|
||||
return s;
|
||||
}
|
||||
return new Scope();
|
||||
}
|
||||
|
||||
extern (D) static Scope* createGlobal(Module _module)
|
||||
{
|
||||
Scope* sc = Scope.alloc();
|
||||
*sc = Scope.init;
|
||||
sc._module = _module;
|
||||
sc.minst = _module;
|
||||
sc.scopesym = new ScopeDsymbol();
|
||||
sc.scopesym.symtab = new DsymbolTable();
|
||||
// Add top level package as member of this global scope
|
||||
Dsymbol m = _module;
|
||||
while (m.parent)
|
||||
m = m.parent;
|
||||
m.addMember(null, sc.scopesym);
|
||||
m.parent = null; // got changed by addMember()
|
||||
if (_module.isCFile)
|
||||
sc.flags |= SCOPE.Cfile;
|
||||
// Create the module scope underneath the global scope
|
||||
sc = sc.push(_module);
|
||||
sc.parent = _module;
|
||||
return sc;
|
||||
}
|
||||
|
||||
extern (C++) Scope* copy()
|
||||
{
|
||||
Scope* sc = Scope.alloc();
|
||||
*sc = this;
|
||||
/* https://issues.dlang.org/show_bug.cgi?id=11777
|
||||
* The copied scope should not inherit fieldinit.
|
||||
*/
|
||||
sc.ctorflow.fieldinit = null;
|
||||
return sc;
|
||||
}
|
||||
|
||||
extern (C++) Scope* push()
|
||||
{
|
||||
Scope* s = copy();
|
||||
//printf("Scope::push(this = %p) new = %p\n", this, s);
|
||||
assert(!(flags & SCOPE.free));
|
||||
s.scopesym = null;
|
||||
s.enclosing = &this;
|
||||
debug
|
||||
{
|
||||
if (enclosing)
|
||||
assert(!(enclosing.flags & SCOPE.free));
|
||||
if (s == enclosing)
|
||||
{
|
||||
printf("this = %p, enclosing = %p, enclosing.enclosing = %p\n", s, &this, enclosing);
|
||||
}
|
||||
assert(s != enclosing);
|
||||
}
|
||||
s.slabel = null;
|
||||
s.nofree = false;
|
||||
s.ctorflow.fieldinit = ctorflow.fieldinit.arraydup;
|
||||
s.flags = (flags & PersistentFlags);
|
||||
s.lastdc = null;
|
||||
assert(&this != s);
|
||||
return s;
|
||||
}
|
||||
|
||||
extern (C++) Scope* push(ScopeDsymbol ss)
|
||||
{
|
||||
//printf("Scope::push(%s)\n", ss.toChars());
|
||||
Scope* s = push();
|
||||
s.scopesym = ss;
|
||||
return s;
|
||||
}
|
||||
|
||||
extern (C++) Scope* pop()
|
||||
{
|
||||
//printf("Scope::pop() %p nofree = %d\n", this, nofree);
|
||||
if (enclosing)
|
||||
enclosing.ctorflow.OR(ctorflow);
|
||||
ctorflow.freeFieldinit();
|
||||
|
||||
Scope* enc = enclosing;
|
||||
if (!nofree)
|
||||
{
|
||||
if (mem.isGCEnabled)
|
||||
this = this.init;
|
||||
enclosing = freelist;
|
||||
freelist = &this;
|
||||
flags |= SCOPE.free;
|
||||
}
|
||||
return enc;
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Similar to pop(), but the results in `this` are not folded
|
||||
* into `enclosing`.
|
||||
*/
|
||||
extern (D) void detach()
|
||||
{
|
||||
ctorflow.freeFieldinit();
|
||||
enclosing = null;
|
||||
pop();
|
||||
}
|
||||
|
||||
extern (C++) Scope* startCTFE()
|
||||
{
|
||||
Scope* sc = this.push();
|
||||
sc.flags = this.flags | SCOPE.ctfe;
|
||||
version (none)
|
||||
{
|
||||
/* TODO: Currently this is not possible, because we need to
|
||||
* unspeculative some types and symbols if they are necessary for the
|
||||
* final executable. Consider:
|
||||
*
|
||||
* struct S(T) {
|
||||
* string toString() const { return "instantiated"; }
|
||||
* }
|
||||
* enum x = S!int();
|
||||
* void main() {
|
||||
* // To call x.toString in runtime, compiler should unspeculative S!int.
|
||||
* assert(x.toString() == "instantiated");
|
||||
* }
|
||||
*/
|
||||
// If a template is instantiated from CT evaluated expression,
|
||||
// compiler can elide its code generation.
|
||||
sc.tinst = null;
|
||||
sc.minst = null;
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
|
||||
extern (C++) Scope* endCTFE()
|
||||
{
|
||||
assert(flags & SCOPE.ctfe);
|
||||
return pop();
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
* Merge results of `ctorflow` into `this`.
|
||||
* Params:
|
||||
* loc = for error messages
|
||||
* ctorflow = flow results to merge in
|
||||
*/
|
||||
extern (D) void merge(const ref Loc loc, const ref CtorFlow ctorflow)
|
||||
{
|
||||
if (!mergeCallSuper(this.ctorflow.callSuper, ctorflow.callSuper))
|
||||
error(loc, "one path skips constructor");
|
||||
|
||||
const fies = ctorflow.fieldinit;
|
||||
if (this.ctorflow.fieldinit.length && fies.length)
|
||||
{
|
||||
FuncDeclaration f = func;
|
||||
if (fes)
|
||||
f = fes.func;
|
||||
auto ad = f.isMemberDecl();
|
||||
assert(ad);
|
||||
foreach (i, v; ad.fields)
|
||||
{
|
||||
bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested());
|
||||
auto fieldInit = &this.ctorflow.fieldinit[i];
|
||||
const fiesCurrent = fies[i];
|
||||
if (fieldInit.loc is Loc.init)
|
||||
fieldInit.loc = fiesCurrent.loc;
|
||||
if (!mergeFieldInit(this.ctorflow.fieldinit[i].csx, fiesCurrent.csx) && mustInit)
|
||||
{
|
||||
error(loc, "one path skips field `%s`", v.toChars());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************************
|
||||
* Perform unqualified name lookup by following the chain of scopes up
|
||||
* until found.
|
||||
*
|
||||
* Params:
|
||||
* loc = location to use for error messages
|
||||
* ident = name to look up
|
||||
* pscopesym = if supplied and name is found, set to scope that ident was found in
|
||||
* flags = modify search based on flags
|
||||
*
|
||||
* Returns:
|
||||
* symbol if found, null if not
|
||||
*/
|
||||
extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone)
|
||||
{
|
||||
version (LOGSEARCH)
|
||||
{
|
||||
printf("Scope.search(%p, '%s' flags=x%x)\n", &this, ident.toChars(), flags);
|
||||
// Print scope chain
|
||||
for (Scope* sc = &this; sc; sc = sc.enclosing)
|
||||
{
|
||||
if (!sc.scopesym)
|
||||
continue;
|
||||
printf("\tscope %s\n", sc.scopesym.toChars());
|
||||
}
|
||||
|
||||
static void printMsg(string txt, Dsymbol s)
|
||||
{
|
||||
printf("%.*s %s.%s, kind = '%s'\n", cast(int)txt.length, txt.ptr,
|
||||
s.parent ? s.parent.toChars() : "", s.toChars(), s.kind());
|
||||
}
|
||||
}
|
||||
|
||||
// This function is called only for unqualified lookup
|
||||
assert(!(flags & (SearchLocalsOnly | SearchImportsOnly)));
|
||||
|
||||
/* If ident is "start at module scope", only look at module scope
|
||||
*/
|
||||
if (ident == Id.empty)
|
||||
{
|
||||
// Look for module scope
|
||||
for (Scope* sc = &this; sc; sc = sc.enclosing)
|
||||
{
|
||||
assert(sc != sc.enclosing);
|
||||
if (!sc.scopesym)
|
||||
continue;
|
||||
if (Dsymbol s = sc.scopesym.isModule())
|
||||
{
|
||||
//printMsg("\tfound", s);
|
||||
if (pscopesym)
|
||||
*pscopesym = sc.scopesym;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, int flags, Expression* exp)
|
||||
{
|
||||
import dmd.mtype;
|
||||
if (!ad || !ad.aliasthis)
|
||||
return null;
|
||||
|
||||
Declaration decl = ad.aliasthis.sym.isDeclaration();
|
||||
if (!decl)
|
||||
return null;
|
||||
|
||||
Type t = decl.type;
|
||||
ScopeDsymbol sds;
|
||||
TypeClass tc;
|
||||
TypeStruct ts;
|
||||
switch(t.ty)
|
||||
{
|
||||
case Tstruct:
|
||||
ts = cast(TypeStruct)t;
|
||||
sds = ts.sym;
|
||||
break;
|
||||
case Tclass:
|
||||
tc = cast(TypeClass)t;
|
||||
sds = tc.sym;
|
||||
break;
|
||||
case Tinstance:
|
||||
sds = (cast(TypeInstance)t).tempinst;
|
||||
break;
|
||||
case Tenum:
|
||||
sds = (cast(TypeEnum)t).sym;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (!sds)
|
||||
return null;
|
||||
|
||||
Dsymbol ret = sds.search(loc, ident, flags);
|
||||
if (ret)
|
||||
{
|
||||
*exp = new DotIdExp(loc, *exp, ad.aliasthis.ident);
|
||||
*exp = new DotIdExp(loc, *exp, ident);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!ts && !tc)
|
||||
return null;
|
||||
|
||||
Dsymbol s;
|
||||
*exp = new DotIdExp(loc, *exp, ad.aliasthis.ident);
|
||||
if (ts && !(ts.att & AliasThisRec.tracing))
|
||||
{
|
||||
ts.att = cast(AliasThisRec)(ts.att | AliasThisRec.tracing);
|
||||
s = checkAliasThis(sds.isAggregateDeclaration(), ident, flags, exp);
|
||||
ts.att = cast(AliasThisRec)(ts.att & ~AliasThisRec.tracing);
|
||||
}
|
||||
else if(tc && !(tc.att & AliasThisRec.tracing))
|
||||
{
|
||||
tc.att = cast(AliasThisRec)(tc.att | AliasThisRec.tracing);
|
||||
s = checkAliasThis(sds.isAggregateDeclaration(), ident, flags, exp);
|
||||
tc.att = cast(AliasThisRec)(tc.att & ~AliasThisRec.tracing);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
Dsymbol searchScopes(int flags)
|
||||
{
|
||||
for (Scope* sc = &this; sc; sc = sc.enclosing)
|
||||
{
|
||||
assert(sc != sc.enclosing);
|
||||
if (!sc.scopesym)
|
||||
continue;
|
||||
//printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc.scopesym.toChars(), sc.scopesym.kind(), flags);
|
||||
|
||||
if (sc.scopesym.isModule())
|
||||
flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
|
||||
|
||||
if (Dsymbol s = sc.scopesym.search(loc, ident, flags))
|
||||
{
|
||||
if (flags & TagNameSpace)
|
||||
{
|
||||
// ImportC: if symbol is not a tag, look for it in tag table
|
||||
if (!s.isScopeDsymbol())
|
||||
{
|
||||
auto ps = cast(void*)s in sc._module.tagSymTab;
|
||||
if (!ps)
|
||||
goto NotFound;
|
||||
s = *ps;
|
||||
}
|
||||
}
|
||||
if (!(flags & (SearchImportsOnly | IgnoreErrors)) &&
|
||||
ident == Id.length && sc.scopesym.isArrayScopeSymbol() &&
|
||||
sc.enclosing && sc.enclosing.search(loc, ident, null, flags))
|
||||
{
|
||||
warning(s.loc, "array `length` hides other `length` name in outer scope");
|
||||
}
|
||||
//printMsg("\tfound local", s);
|
||||
if (pscopesym)
|
||||
*pscopesym = sc.scopesym;
|
||||
return s;
|
||||
}
|
||||
|
||||
NotFound:
|
||||
if (global.params.fixAliasThis)
|
||||
{
|
||||
Expression exp = new ThisExp(loc);
|
||||
Dsymbol aliasSym = checkAliasThis(sc.scopesym.isAggregateDeclaration(), ident, flags, &exp);
|
||||
if (aliasSym)
|
||||
{
|
||||
//printf("found aliassym: %s\n", aliasSym.toChars());
|
||||
if (pscopesym)
|
||||
*pscopesym = new ExpressionDsymbol(exp);
|
||||
return aliasSym;
|
||||
}
|
||||
}
|
||||
|
||||
// Stop when we hit a module, but keep going if that is not just under the global scope
|
||||
if (sc.scopesym.isModule() && !(sc.enclosing && !sc.enclosing.enclosing))
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.flags & SCOPE.ignoresymbolvisibility)
|
||||
flags |= IgnoreSymbolVisibility;
|
||||
|
||||
// First look in local scopes
|
||||
Dsymbol s = searchScopes(flags | SearchLocalsOnly);
|
||||
version (LOGSEARCH) if (s) printMsg("-Scope.search() found local", s);
|
||||
if (!s)
|
||||
{
|
||||
// Second look in imported modules
|
||||
s = searchScopes(flags | SearchImportsOnly);
|
||||
version (LOGSEARCH) if (s) printMsg("-Scope.search() found import", s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
extern (D) Dsymbol search_correct(Identifier ident)
|
||||
{
|
||||
if (global.gag)
|
||||
return null; // don't do it for speculative compiles; too time consuming
|
||||
|
||||
/************************************************
|
||||
* Given the failed search attempt, try to find
|
||||
* one with a close spelling.
|
||||
* Params:
|
||||
* seed = identifier to search for
|
||||
* cost = set to the cost, which rises with each outer scope
|
||||
* Returns:
|
||||
* Dsymbol if found, null if not
|
||||
*/
|
||||
extern (D) Dsymbol scope_search_fp(const(char)[] seed, out int cost)
|
||||
{
|
||||
//printf("scope_search_fp('%s')\n", seed);
|
||||
/* If not in the lexer's string table, it certainly isn't in the symbol table.
|
||||
* Doing this first is a lot faster.
|
||||
*/
|
||||
if (!seed.length)
|
||||
return null;
|
||||
Identifier id = Identifier.lookup(seed);
|
||||
if (!id)
|
||||
return null;
|
||||
Scope* sc = &this;
|
||||
Module.clearCache();
|
||||
Dsymbol scopesym = null;
|
||||
Dsymbol s = sc.search(Loc.initial, id, &scopesym, IgnoreErrors);
|
||||
if (!s)
|
||||
return null;
|
||||
|
||||
// Do not show `@disable`d declarations
|
||||
if (auto decl = s.isDeclaration())
|
||||
if (decl.storage_class & STC.disable)
|
||||
return null;
|
||||
// Or `deprecated` ones if we're not in a deprecated scope
|
||||
if (s.isDeprecated() && !sc.isDeprecated())
|
||||
return null;
|
||||
|
||||
for (cost = 0; sc; sc = sc.enclosing, ++cost)
|
||||
if (sc.scopesym == scopesym)
|
||||
break;
|
||||
if (scopesym != s.parent)
|
||||
{
|
||||
++cost; // got to the symbol through an import
|
||||
if (s.visible().kind == Visibility.Kind.private_)
|
||||
return null;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
Dsymbol scopesym = null;
|
||||
// search for exact name first
|
||||
if (auto s = search(Loc.initial, ident, &scopesym, IgnoreErrors))
|
||||
return s;
|
||||
return speller!scope_search_fp(ident.toString());
|
||||
}
|
||||
|
||||
/************************************
|
||||
* Maybe `ident` was a C or C++ name. Check for that,
|
||||
* and suggest the D equivalent.
|
||||
* Params:
|
||||
* ident = unknown identifier
|
||||
* Returns:
|
||||
* D identifier string if found, null if not
|
||||
*/
|
||||
extern (D) static const(char)* search_correct_C(Identifier ident)
|
||||
{
|
||||
import dmd.astenums : Twchar;
|
||||
TOK tok;
|
||||
if (ident == Id.NULL)
|
||||
tok = TOK.null_;
|
||||
else if (ident == Id.TRUE)
|
||||
tok = TOK.true_;
|
||||
else if (ident == Id.FALSE)
|
||||
tok = TOK.false_;
|
||||
else if (ident == Id.unsigned)
|
||||
tok = TOK.uns32;
|
||||
else if (ident == Id.wchar_t)
|
||||
tok = target.c.wchar_tsize == 2 ? TOK.wchar_ : TOK.dchar_;
|
||||
else
|
||||
return null;
|
||||
return Token.toChars(tok);
|
||||
}
|
||||
|
||||
/***************************
|
||||
* Find the innermost scope with a symbol table.
|
||||
* Returns:
|
||||
* innermost scope, null if none
|
||||
*/
|
||||
extern (D) Scope* inner() return
|
||||
{
|
||||
for (Scope* sc = &this; sc; sc = sc.enclosing)
|
||||
{
|
||||
if (sc.scopesym)
|
||||
return sc;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/******************************
|
||||
* Add symbol s to innermost symbol table.
|
||||
* Params:
|
||||
* s = symbol to insert
|
||||
* Returns:
|
||||
* null if already in table, `s` if not
|
||||
*/
|
||||
extern (D) Dsymbol insert(Dsymbol s)
|
||||
{
|
||||
//printf("insert() %s\n", s.toChars());
|
||||
if (VarDeclaration vd = s.isVarDeclaration())
|
||||
{
|
||||
if (lastVar)
|
||||
vd.lastVar = lastVar;
|
||||
lastVar = vd;
|
||||
}
|
||||
else if (WithScopeSymbol ss = s.isWithScopeSymbol())
|
||||
{
|
||||
if (VarDeclaration vd = ss.withstate.wthis)
|
||||
{
|
||||
if (lastVar)
|
||||
vd.lastVar = lastVar;
|
||||
lastVar = vd;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
auto scopesym = inner().scopesym;
|
||||
//printf("\t\tscopesym = %p\n", scopesym);
|
||||
if (!scopesym.symtab)
|
||||
scopesym.symtab = new DsymbolTable();
|
||||
if (!(flags & SCOPE.Cfile))
|
||||
return scopesym.symtabInsert(s);
|
||||
|
||||
// ImportC insert
|
||||
if (!scopesym.symtabInsert(s)) // if already in table
|
||||
{
|
||||
Dsymbol s2 = scopesym.symtabLookup(s, s.ident); // s2 is existing entry
|
||||
return handleTagSymbols(this, s, s2, scopesym);
|
||||
}
|
||||
return s; // inserted
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* Search enclosing scopes for ScopeDsymbol.
|
||||
*/
|
||||
ScopeDsymbol getScopesym()
|
||||
{
|
||||
for (Scope* sc = &this; sc; sc = sc.enclosing)
|
||||
{
|
||||
if (sc.scopesym)
|
||||
return sc.scopesym;
|
||||
}
|
||||
return null; // not found
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* Search enclosing scopes for ClassDeclaration.
|
||||
*/
|
||||
extern (C++) ClassDeclaration getClassScope()
|
||||
{
|
||||
for (Scope* sc = &this; sc; sc = sc.enclosing)
|
||||
{
|
||||
if (!sc.scopesym)
|
||||
continue;
|
||||
if (ClassDeclaration cd = sc.scopesym.isClassDeclaration())
|
||||
return cd;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* Search enclosing scopes for ClassDeclaration.
|
||||
*/
|
||||
extern (C++) AggregateDeclaration getStructClassScope()
|
||||
{
|
||||
for (Scope* sc = &this; sc; sc = sc.enclosing)
|
||||
{
|
||||
if (!sc.scopesym)
|
||||
continue;
|
||||
if (AggregateDeclaration ad = sc.scopesym.isClassDeclaration())
|
||||
return ad;
|
||||
if (AggregateDeclaration ad = sc.scopesym.isStructDeclaration())
|
||||
return ad;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
* For TemplateDeclarations, we need to remember the Scope
|
||||
* where it was declared. So mark the Scope as not
|
||||
* to be free'd.
|
||||
*/
|
||||
extern (D) void setNoFree()
|
||||
{
|
||||
//int i = 0;
|
||||
//printf("Scope::setNoFree(this = %p)\n", this);
|
||||
for (Scope* sc = &this; sc; sc = sc.enclosing)
|
||||
{
|
||||
//printf("\tsc = %p\n", sc);
|
||||
sc.nofree = true;
|
||||
assert(!(flags & SCOPE.free));
|
||||
//assert(sc != sc.enclosing);
|
||||
//assert(!sc.enclosing || sc != sc.enclosing.enclosing);
|
||||
//if (++i == 10)
|
||||
// assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
structalign_t alignment()
|
||||
{
|
||||
if (aligndecl)
|
||||
return aligndecl.getAlignment(&this);
|
||||
else
|
||||
return STRUCTALIGN_DEFAULT;
|
||||
}
|
||||
|
||||
/**********************************
|
||||
* Checks whether the current scope (or any of its parents) is deprecated.
|
||||
*
|
||||
* Returns: `true` if this or any parent scope is deprecated, `false` otherwise`
|
||||
*/
|
||||
extern(C++) bool isDeprecated() @safe @nogc pure nothrow const
|
||||
{
|
||||
for (const(Dsymbol)* sp = &(this.parent); *sp; sp = &(sp.parent))
|
||||
{
|
||||
if (sp.isDeprecated())
|
||||
return true;
|
||||
}
|
||||
for (const(Scope)* sc2 = &this; sc2; sc2 = sc2.enclosing)
|
||||
{
|
||||
if (sc2.scopesym && sc2.scopesym.isDeprecated())
|
||||
return true;
|
||||
|
||||
// If inside a StorageClassDeclaration that is deprecated
|
||||
if (sc2.stc & STC.deprecated_)
|
||||
return true;
|
||||
}
|
||||
if (_module.md && _module.md.isdeprecated)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
1303
gcc/d/dmd/dstruct.c
1303
gcc/d/dmd/dstruct.c
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue