aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd/escape.c
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2019-06-18 20:42:10 +0200
committerIain Buclaw <ibuclaw@gdcproject.org>2021-11-30 16:53:28 +0100
commit5fee5ec362f7a243f459e6378fd49dfc89dc9fb5 (patch)
tree61d1bdbca854a903c0860406f457f06b2040be7a /gcc/d/dmd/escape.c
parentb3f60112edcb85b459e60f66c44a55138b1cef49 (diff)
downloadgcc-5fee5ec362f7a243f459e6378fd49dfc89dc9fb5.zip
gcc-5fee5ec362f7a243f459e6378fd49dfc89dc9fb5.tar.gz
gcc-5fee5ec362f7a243f459e6378fd49dfc89dc9fb5.tar.bz2
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.
Diffstat (limited to 'gcc/d/dmd/escape.c')
-rw-r--r--gcc/d/dmd/escape.c1234
1 files changed, 0 insertions, 1234 deletions
diff --git a/gcc/d/dmd/escape.c b/gcc/d/dmd/escape.c
deleted file mode 100644
index cd0382b..0000000
--- a/gcc/d/dmd/escape.c
+++ /dev/null
@@ -1,1234 +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/escape.c
- */
-
-#include "mars.h"
-#include "init.h"
-#include "expression.h"
-#include "scope.h"
-#include "aggregate.h"
-#include "declaration.h"
-#include "module.h"
-
-/************************************
- * Aggregate the data collected by the escapeBy??() functions.
- */
-struct EscapeByResults
-{
- VarDeclarations byref; // array into which variables being returned by ref are inserted
- VarDeclarations byvalue; // array into which variables with values containing pointers are inserted
- FuncDeclarations byfunc; // nested functions that are turned into delegates
- Expressions byexp; // array into which temporaries being returned by ref are inserted
-};
-
-static bool checkReturnEscapeImpl(Scope *sc, Expression *e, bool refs, bool gag);
-static void inferReturn(FuncDeclaration *fd, VarDeclaration *v);
-static void escapeByValue(Expression *e, EscapeByResults *er);
-static void escapeByRef(Expression *e, EscapeByResults *er);
-static void findAllOuterAccessedVariables(FuncDeclaration *fd, VarDeclarations *vars);
-
-/* 'v' is assigned unsafely to 'par'
-*/
-static void unsafeAssign(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag,
- bool &result, VarDeclaration *v, const char *desc)
-{
- if (global.params.vsafe && sc->func->setUnsafe())
- {
- if (!gag)
- error(arg->loc, "%s %s assigned to non-scope parameter %s calling %s",
- desc, v->toChars(),
- par ? par->toChars() : "unnamed",
- fdc ? fdc->toPrettyChars() : "indirectly");
- result = true;
- }
-}
-
-/****************************************
- * Function parameter par is being initialized to arg,
- * and par may escape.
- * Detect if scoped values can escape this way.
- * Print error messages when these are detected.
- * Params:
- * sc = used to determine current function and module
- * par = identifier of function parameter
- * arg = initializer for param
- * gag = do not print error messages
- * Returns:
- * true if pointers to the stack can escape via assignment
- */
-bool checkParamArgumentEscape(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag)
-{
- //printf("checkParamArgumentEscape(arg: %s par: %s)\n", arg->toChars(), par->toChars());
- //printf("type = %s, %d\n", arg->type->toChars(), arg->type->hasPointers());
-
- if (!arg->type->hasPointers())
- return false;
-
- EscapeByResults er;
-
- escapeByValue(arg, &er);
-
- if (!er.byref.length && !er.byvalue.length && !er.byfunc.length && !er.byexp.length)
- return false;
-
- bool result = false;
-
- for (size_t i = 0; i < er.byvalue.length; i++)
- {
- //printf("byvalue %s\n", v->toChars());
- VarDeclaration *v = er.byvalue[i];
- if (v->isDataseg())
- continue;
-
- Dsymbol *p = v->toParent2();
-
- v->storage_class &= ~STCmaybescope;
-
- if (v->isScope())
- {
- unsafeAssign(sc, fdc, par, arg, gag, result, v, "scope variable");
- }
- else if (v->storage_class & STCvariadic && p == sc->func)
- {
- Type *tb = v->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- unsafeAssign(sc, fdc, par, arg, gag, result, v, "variadic variable");
- }
- }
- else
- {
- /* v is not 'scope', and is assigned to a parameter that may escape.
- * Therefore, v can never be 'scope'.
- */
- v->doNotInferScope = true;
- }
- }
-
- for (size_t i = 0; i < er.byref.length; i++)
- {
- VarDeclaration *v = er.byref[i];
- if (v->isDataseg())
- continue;
-
- Dsymbol *p = v->toParent2();
-
- v->storage_class &= ~STCmaybescope;
-
- if ((v->storage_class & (STCref | STCout)) == 0 && p == sc->func)
- {
- unsafeAssign(sc, fdc, par, arg, gag, result, v, "reference to local variable");
- continue;
- }
- }
-
- for (size_t i = 0; i < er.byfunc.length; i++)
- {
- FuncDeclaration *fd = er.byfunc[i];
- //printf("fd = %s, %d\n", fd->toChars(), fd->tookAddressOf);
- VarDeclarations vars;
- findAllOuterAccessedVariables(fd, &vars);
-
- for (size_t j = 0; j < vars.length; j++)
- {
- VarDeclaration *v = vars[j];
- //printf("v = %s\n", v->toChars());
- assert(!v->isDataseg()); // these are not put in the closureVars[]
-
- Dsymbol *p = v->toParent2();
-
- v->storage_class &= ~STCmaybescope;
-
- if ((v->storage_class & (STCref | STCout | STCscope)) && p == sc->func)
- {
- unsafeAssign(sc, fdc, par, arg, gag, result, v, "reference to local");
- continue;
- }
- }
- }
-
- for (size_t i = 0; i < er.byexp.length; i++)
- {
- Expression *ee = er.byexp[i];
- if (sc->func->setUnsafe())
- {
- if (!gag)
- error(ee->loc, "reference to stack allocated value returned by %s assigned to non-scope parameter %s",
- ee->toChars(),
- par ? par->toChars() : "unnamed");
- result = true;
- }
- }
-
- return result;
-}
-
-/****************************************
- * Given an AssignExp, determine if the lvalue will cause
- * the contents of the rvalue to escape.
- * Print error messages when these are detected.
- * Infer 'scope' for the lvalue where possible, in order
- * to eliminate the error.
- * Params:
- * sc = used to determine current function and module
- * ae = AssignExp to check for any pointers to the stack
- * gag = do not print error messages
- * Returns:
- * true if pointers to the stack can escape via assignment
- */
-bool checkAssignEscape(Scope *sc, Expression *e, bool gag)
-{
- //printf("checkAssignEscape(e: %s)\n", e->toChars());
- if (e->op != TOKassign && e->op != TOKblit && e->op != TOKconstruct)
- return false;
- AssignExp *ae = (AssignExp *)e;
- Expression *e1 = ae->e1;
- Expression *e2 = ae->e2;
- //printf("type = %s, %d\n", e1->type->toChars(), e1->type->hasPointers());
-
- if (!e1->type->hasPointers())
- return false;
-
- if (e1->op == TOKslice)
- return false;
-
- EscapeByResults er;
-
- escapeByValue(e2, &er);
-
- if (!er.byref.length && !er.byvalue.length && !er.byfunc.length && !er.byexp.length)
- return false;
-
- VarDeclaration *va = NULL;
- while (e1->op == TOKdotvar)
- e1 = ((DotVarExp *)e1)->e1;
-
- if (e1->op == TOKvar)
- va = ((VarExp *)e1)->var->isVarDeclaration();
- else if (e1->op == TOKthis)
- va = ((ThisExp *)e1)->var->isVarDeclaration();
- else if (e1->op == TOKindex)
- {
- IndexExp *ie = (IndexExp *)e1;
- if (ie->e1->op == TOKvar && ie->e1->type->toBasetype()->ty == Tsarray)
- va = ((VarExp *)ie->e1)->var->isVarDeclaration();
- }
-
- // Try to infer 'scope' for va if in a function not marked @system
- bool inferScope = false;
- if (va && sc->func && sc->func->type && sc->func->type->ty == Tfunction)
- inferScope = ((TypeFunction *)sc->func->type)->trust != TRUSTsystem;
-
- bool result = false;
- for (size_t i = 0; i < er.byvalue.length; i++)
- {
- VarDeclaration *v = er.byvalue[i];
- //printf("byvalue: %s\n", v->toChars());
- if (v->isDataseg())
- continue;
-
- Dsymbol *p = v->toParent2();
-
- if (!(va && va->isScope()))
- v->storage_class &= ~STCmaybescope;
-
- if (v->isScope())
- {
- if (va && va->isScope() && va->storage_class & STCreturn && !(v->storage_class & STCreturn) &&
- sc->func->setUnsafe())
- {
- if (!gag)
- error(ae->loc, "scope variable %s assigned to return scope %s", v->toChars(), va->toChars());
- result = true;
- continue;
- }
-
- // If va's lifetime encloses v's, then error
- if (va &&
- ((va->enclosesLifetimeOf(v) && !(v->storage_class & STCparameter)) ||
- // va is class reference
- (ae->e1->op == TOKdotvar && va->type->toBasetype()->ty == Tclass && (va->enclosesLifetimeOf(v) || !va->isScope())) ||
- va->storage_class & STCref) &&
- sc->func->setUnsafe())
- {
- if (!gag)
- error(ae->loc, "scope variable %s assigned to %s with longer lifetime", v->toChars(), va->toChars());
- result = true;
- continue;
- }
-
- if (va && !va->isDataseg() && !va->doNotInferScope)
- {
- if (!va->isScope() && inferScope)
- { //printf("inferring scope for %s\n", va->toChars());
- va->storage_class |= STCscope | STCscopeinferred;
- va->storage_class |= v->storage_class & STCreturn;
- }
- continue;
- }
- if (sc->func->setUnsafe())
- {
- if (!gag)
- error(ae->loc, "scope variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
- result = true;
- }
- }
- else if (v->storage_class & STCvariadic && p == sc->func)
- {
- Type *tb = v->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (va && !va->isDataseg() && !va->doNotInferScope)
- {
- if (!va->isScope() && inferScope)
- { //printf("inferring scope for %s\n", va->toChars());
- va->storage_class |= STCscope | STCscopeinferred;
- }
- continue;
- }
- if (sc->func->setUnsafe())
- {
- if (!gag)
- error(ae->loc, "variadic variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
- result = true;
- }
- }
- }
- else
- {
- /* v is not 'scope', and we didn't check the scope of where we assigned it to.
- * It may escape via that assignment, therefore, v can never be 'scope'.
- */
- v->doNotInferScope = true;
- }
- }
-
- for (size_t i = 0; i < er.byref.length; i++)
- {
- VarDeclaration *v = er.byref[i];
- //printf("byref: %s\n", v->toChars());
- if (v->isDataseg())
- continue;
-
- Dsymbol *p = v->toParent2();
-
- // If va's lifetime encloses v's, then error
- if (va &&
- ((va->enclosesLifetimeOf(v) && !(v->storage_class & STCparameter)) || va->storage_class & STCref) &&
- sc->func->setUnsafe())
- {
- if (!gag)
- error(ae->loc, "address of variable %s assigned to %s with longer lifetime", v->toChars(), va->toChars());
- result = true;
- continue;
- }
-
- if (!(va && va->isScope()))
- v->storage_class &= ~STCmaybescope;
-
- if ((v->storage_class & (STCref | STCout)) == 0 && p == sc->func)
- {
- if (va && !va->isDataseg() && !va->doNotInferScope)
- {
- if (!va->isScope() && inferScope)
- { //printf("inferring scope for %s\n", va->toChars());
- va->storage_class |= STCscope | STCscopeinferred;
- }
- continue;
- }
- if (sc->func->setUnsafe())
- {
- if (!gag)
- error(ae->loc, "reference to local variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
- result = true;
- }
- continue;
- }
- }
-
- for (size_t i = 0; i < er.byfunc.length; i++)
- {
- FuncDeclaration *fd = er.byfunc[i];
- //printf("fd = %s, %d\n", fd->toChars(), fd->tookAddressOf);
- VarDeclarations vars;
- findAllOuterAccessedVariables(fd, &vars);
-
- for (size_t j = 0; j < vars.length; j++)
- {
- VarDeclaration *v = vars[j];
- //printf("v = %s\n", v->toChars());
- assert(!v->isDataseg()); // these are not put in the closureVars[]
-
- Dsymbol *p = v->toParent2();
-
- if (!(va && va->isScope()))
- v->storage_class &= ~STCmaybescope;
-
- if ((v->storage_class & (STCref | STCout | STCscope)) && p == sc->func)
- {
- if (va && !va->isDataseg() && !va->doNotInferScope)
- {
- /* Don't infer STCscope for va, because then a closure
- * won't be generated for sc->func.
- */
- //if (!va->isScope() && inferScope)
- //va->storage_class |= STCscope | STCscopeinferred;
- continue;
- }
- if (sc->func->setUnsafe())
- {
- if (!gag)
- error(ae->loc, "reference to local %s assigned to non-scope %s in @safe code", v->toChars(), e1->toChars());
- result = true;
- }
- continue;
- }
- }
- }
-
- for (size_t i = 0; i < er.byexp.length; i++)
- {
- Expression *ee = er.byexp[i];
- if (va && !va->isDataseg() && !va->doNotInferScope)
- {
- if (!va->isScope() && inferScope)
- { //printf("inferring scope for %s\n", va->toChars());
- va->storage_class |= STCscope | STCscopeinferred;
- }
- continue;
- }
- if (sc->func->setUnsafe())
- {
- if (!gag)
- error(ee->loc, "reference to stack allocated value returned by %s assigned to non-scope %s",
- ee->toChars(), e1->toChars());
- result = true;
- }
- }
-
- return result;
-}
-
-/************************************
- * Detect cases where pointers to the stack can 'escape' the
- * lifetime of the stack frame when throwing `e`.
- * Print error messages when these are detected.
- * Params:
- * sc = used to determine current function and module
- * e = expression to check for any pointers to the stack
- * gag = do not print error messages
- * Returns:
- * true if pointers to the stack can escape
- */
-bool checkThrowEscape(Scope *sc, Expression *e, bool gag)
-{
- //printf("[%s] checkThrowEscape, e = %s\n", e->loc->toChars(), e->toChars());
- EscapeByResults er;
-
- escapeByValue(e, &er);
-
- if (!er.byref.length && !er.byvalue.length && !er.byexp.length)
- return false;
-
- bool result = false;
- for (size_t i = 0; i < er.byvalue.length; i++)
- {
- VarDeclaration *v = er.byvalue[i];
- //printf("byvalue %s\n", v->toChars());
- if (v->isDataseg())
- continue;
-
- if (v->isScope())
- {
- if (sc->_module && sc->_module->isRoot())
- {
- // Only look for errors if in module listed on command line
- if (global.params.vsafe) // https://issues.dlang.org/show_bug.cgi?id=17029
- {
- if (!gag)
- error(e->loc, "scope variable %s may not be thrown", v->toChars());
- result = true;
- }
- continue;
- }
- }
- else
- {
- //printf("no infer for %s\n", v->toChars());
- v->doNotInferScope = true;
- }
- }
- return result;
-}
-
-/************************************
- * Detect cases where pointers to the stack can 'escape' the
- * lifetime of the stack frame by returning 'e' by value.
- * Params:
- * sc = used to determine current function and module
- * e = expression to check for any pointers to the stack
- * gag = do not print error messages
- * Returns:
- * true if pointers to the stack can escape
- */
-
-bool checkReturnEscape(Scope *sc, Expression *e, bool gag)
-{
- //printf("[%s] checkReturnEscape, e = %s\n", e->loc->toChars(), e->toChars());
- return checkReturnEscapeImpl(sc, e, false, gag);
-}
-
-/************************************
- * Detect cases where returning 'e' by ref can result in a reference to the stack
- * being returned.
- * Print error messages when these are detected.
- * Params:
- * sc = used to determine current function and module
- * e = expression to check
- * gag = do not print error messages
- * Returns:
- * true if references to the stack can escape
- */
-bool checkReturnEscapeRef(Scope *sc, Expression *e, bool gag)
-{
- //printf("[%s] checkReturnEscapeRef, e = %s\n", e->loc.toChars(), e->toChars());
- //printf("current function %s\n", sc->func->toChars());
- //printf("parent2 function %s\n", sc->func->toParent2()->toChars());
-
- return checkReturnEscapeImpl(sc, e, true, gag);
-}
-
-static void escapingRef(VarDeclaration *v, Expression *e, bool &result, bool gag)
-{
- if (!gag)
- {
- const char *msg;
- if (v->storage_class & STCparameter)
- msg = "returning `%s` escapes a reference to parameter `%s`, perhaps annotate with `return`";
- else
- msg = "returning `%s` escapes a reference to local variable `%s`";
- error(e->loc, msg, e->toChars(), v->toChars());
- }
- result = true;
-}
-
-static bool checkReturnEscapeImpl(Scope *sc, Expression *e, bool refs, bool gag)
-{
- //printf("[%s] checkReturnEscapeImpl, e = %s\n", e->loc->toChars(), e->toChars());
- EscapeByResults er;
-
- if (refs)
- escapeByRef(e, &er);
- else
- escapeByValue(e, &er);
-
- if (!er.byref.length && !er.byvalue.length && !er.byexp.length)
- return false;
-
- bool result = false;
- for (size_t i = 0; i < er.byvalue.length; i++)
- {
- VarDeclaration *v = er.byvalue[i];
- //printf("byvalue %s\n", v->toChars());
- if (v->isDataseg())
- continue;
-
- Dsymbol *p = v->toParent2();
-
- if ((v->isScope() || (v->storage_class & STCmaybescope)) &&
- !(v->storage_class & STCreturn) &&
- v->isParameter() &&
- sc->func->flags & FUNCFLAGreturnInprocess &&
- p == sc->func)
- {
- inferReturn(sc->func, v); // infer addition of 'return'
- continue;
- }
-
- if (v->isScope())
- {
- if (v->storage_class & STCreturn)
- continue;
-
- if (sc->_module && sc->_module->isRoot() &&
- /* This case comes up when the ReturnStatement of a __foreachbody is
- * checked for escapes by the caller of __foreachbody. Skip it.
- *
- * struct S { static int opApply(int delegate(S*) dg); }
- * S* foo() {
- * foreach (S* s; S) // create __foreachbody for body of foreach
- * return s; // s is inferred as 'scope' but incorrectly tested in foo()
- * return null; }
- */
- !(!refs && p->parent == sc->func))
- {
- // Only look for errors if in module listed on command line
- if (global.params.vsafe) // https://issues.dlang.org/show_bug.cgi?id=17029
- {
- if (!gag)
- error(e->loc, "scope variable %s may not be returned", v->toChars());
- result = true;
- }
- continue;
- }
- }
- else if (v->storage_class & STCvariadic && p == sc->func)
- {
- Type *tb = v->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!gag)
- error(e->loc, "returning `%s` escapes a reference to variadic parameter `%s`", e->toChars(), v->toChars());
- result = false;
- }
- }
- else
- {
- //printf("no infer for %s\n", v->toChars());
- v->doNotInferScope = true;
- }
- }
-
- for (size_t i = 0; i < er.byref.length; i++)
- {
- VarDeclaration *v = er.byref[i];
- //printf("byref %s\n", v->toChars());
- if (v->isDataseg())
- continue;
-
- Dsymbol *p = v->toParent2();
-
- if ((v->storage_class & (STCref | STCout)) == 0)
- {
- if (p == sc->func)
- {
- escapingRef(v, e, result, gag);
- continue;
- }
- FuncDeclaration *fd = p->isFuncDeclaration();
- if (fd && sc->func->flags & FUNCFLAGreturnInprocess)
- {
- /* Code like:
- * int x;
- * auto dg = () { return &x; }
- * Making it:
- * auto dg = () return { return &x; }
- * Because dg.ptr points to x, this is returning dt.ptr+offset
- */
- if (global.params.vsafe)
- sc->func->storage_class |= STCreturn;
- }
- }
-
- /* Check for returning a ref variable by 'ref', but should be 'return ref'
- * Infer the addition of 'return', or set result to be the offending expression.
- */
- if ( (v->storage_class & (STCref | STCout)) &&
- !(v->storage_class & (STCreturn | STCforeach)))
- {
- if ((sc->func->flags & FUNCFLAGreturnInprocess) && p == sc->func)
- {
- inferReturn(sc->func, v); // infer addition of 'return'
- }
- else if (global.params.useDIP25 &&
- sc->_module && sc->_module->isRoot())
- {
- // Only look for errors if in module listed on command line
-
- if (p == sc->func)
- {
- //printf("escaping reference to local ref variable %s\n", v->toChars());
- //printf("storage class = x%llx\n", v->storage_class);
- escapingRef(v, e, result, gag);
- continue;
- }
- // Don't need to be concerned if v's parent does not return a ref
- FuncDeclaration *fd = p->isFuncDeclaration();
- if (fd && fd->type && fd->type->ty == Tfunction)
- {
- TypeFunction *tf = (TypeFunction *)fd->type;
- if (tf->isref)
- {
- if (!gag)
- error(e->loc, "escaping reference to outer local variable %s", v->toChars());
- result = true;
- continue;
- }
- }
- }
- }
- }
-
- for (size_t i = 0; i < er.byexp.length; i++)
- {
- Expression *ee = er.byexp[i];
- //printf("byexp %s\n", ee->toChars());
- if (!gag)
- error(ee->loc, "escaping reference to stack allocated value returned by %s", ee->toChars());
- result = true;
- }
-
- return result;
-}
-
-
-/*************************************
- * Variable v needs to have 'return' inferred for it.
- * Params:
- * fd = function that v is a parameter to
- * v = parameter that needs to be STCreturn
- */
-
-static void inferReturn(FuncDeclaration *fd, VarDeclaration *v)
-{
- // v is a local in the current function
-
- //printf("for function '%s' inferring 'return' for variable '%s'\n", fd->toChars(), v->toChars());
- v->storage_class |= STCreturn;
-
- TypeFunction *tf = (TypeFunction *)fd->type;
- if (v == fd->vthis)
- {
- /* v is the 'this' reference, so mark the function
- */
- fd->storage_class |= STCreturn;
- if (tf->ty == Tfunction)
- {
- //printf("'this' too %p %s\n", tf, sc->func->toChars());
- tf->isreturn = true;
- }
- }
- else
- {
- // Perform 'return' inference on parameter
- if (tf->ty == Tfunction)
- {
- const size_t dim = tf->parameterList.length();
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *p = tf->parameterList[i];
- if (p->ident == v->ident)
- {
- p->storageClass |= STCreturn;
- break; // there can be only one
- }
- }
- }
- }
-}
-
-
-/****************************************
- * e is an expression to be returned by value, and that value contains pointers.
- * Walk e to determine which variables are possibly being
- * returned by value, such as:
- * int* function(int* p) { return p; }
- * If e is a form of &p, determine which variables have content
- * which is being returned as ref, such as:
- * int* function(int i) { return &i; }
- * Multiple variables can be inserted, because of expressions like this:
- * int function(bool b, int i, int* p) { return b ? &i : p; }
- *
- * No side effects.
- *
- * Params:
- * e = expression to be returned by value
- * er = where to place collected data
- */
-static void escapeByValue(Expression *e, EscapeByResults *er)
-{
- //printf("[%s] escapeByValue, e: %s\n", e->loc.toChars(), e->toChars());
-
- class EscapeVisitor : public Visitor
- {
- public:
- EscapeByResults *er;
-
- EscapeVisitor(EscapeByResults *er)
- : er(er)
- {
- }
-
- void visit(Expression *)
- {
- }
-
- void visit(AddrExp *e)
- {
- escapeByRef(e->e1, er);
- }
-
- void visit(SymOffExp *e)
- {
- VarDeclaration *v = e->var->isVarDeclaration();
- if (v)
- er->byref.push(v);
- }
-
- void visit(VarExp *e)
- {
- VarDeclaration *v = e->var->isVarDeclaration();
- if (v)
- er->byvalue.push(v);
- }
-
- void visit(ThisExp *e)
- {
- if (e->var)
- er->byvalue.push(e->var);
- }
-
- void visit(DotVarExp *e)
- {
- Type *t = e->e1->type->toBasetype();
- if (t->ty == Tstruct)
- e->e1->accept(this);
- }
-
- void visit(DelegateExp *e)
- {
- Type *t = e->e1->type->toBasetype();
- if (t->ty == Tclass || t->ty == Tpointer)
- escapeByValue(e->e1, er);
- else
- escapeByRef(e->e1, er);
- er->byfunc.push(e->func);
- }
-
- void visit(FuncExp *e)
- {
- if (e->fd->tok == TOKdelegate)
- er->byfunc.push(e->fd);
- }
-
- void visit(TupleExp *)
- {
- assert(0); // should have been lowered by now
- }
-
- void visit(ArrayLiteralExp *e)
- {
- Type *tb = e->type->toBasetype();
- if (tb->ty == Tsarray || tb->ty == Tarray)
- {
- if (e->basis)
- e->basis->accept(this);
- for (size_t i = 0; i < e->elements->length; i++)
- {
- Expression *el = (*e->elements)[i];
- if (el)
- el->accept(this);
- }
- }
- }
-
- void visit(StructLiteralExp *e)
- {
- if (e->elements)
- {
- for (size_t i = 0; i < e->elements->length; i++)
- {
- Expression *ex = (*e->elements)[i];
- if (ex)
- ex->accept(this);
- }
- }
- }
-
- void visit(NewExp *e)
- {
- Type *tb = e->newtype->toBasetype();
- if (tb->ty == Tstruct && !e->member && e->arguments)
- {
- for (size_t i = 0; i < e->arguments->length; i++)
- {
- Expression *ex = (*e->arguments)[i];
- if (ex)
- ex->accept(this);
- }
- }
- }
-
- void visit(CastExp *e)
- {
- Type *tb = e->type->toBasetype();
- if (tb->ty == Tarray &&
- e->e1->type->toBasetype()->ty == Tsarray)
- {
- escapeByRef(e->e1, er);
- }
- else
- e->e1->accept(this);
- }
-
- void visit(SliceExp *e)
- {
- if (e->e1->op == TOKvar)
- {
- VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration();
- Type *tb = e->type->toBasetype();
- if (v)
- {
- if (tb->ty == Tsarray)
- return;
- if (v->storage_class & STCvariadic)
- {
- er->byvalue.push(v);
- return;
- }
- }
- }
- Type *t1b = e->e1->type->toBasetype();
- if (t1b->ty == Tsarray)
- {
- Type *tb = e->type->toBasetype();
- if (tb->ty != Tsarray)
- escapeByRef(e->e1, er);
- }
- else
- e->e1->accept(this);
- }
-
- void visit(BinExp *e)
- {
- Type *tb = e->type->toBasetype();
- if (tb->ty == Tpointer)
- {
- e->e1->accept(this);
- e->e2->accept(this);
- }
- }
-
- void visit(BinAssignExp *e)
- {
- e->e1->accept(this);
- }
-
- void visit(AssignExp *e)
- {
- e->e1->accept(this);
- }
-
- void visit(CommaExp *e)
- {
- e->e2->accept(this);
- }
-
- void visit(CondExp *e)
- {
- e->e1->accept(this);
- e->e2->accept(this);
- }
-
- void visit(CallExp *e)
- {
- //printf("CallExp(): %s\n", e->toChars());
- /* Check each argument that is
- * passed as 'return scope'.
- */
- Type *t1 = e->e1->type->toBasetype();
- TypeFunction *tf = NULL;
- TypeDelegate *dg = NULL;
- if (t1->ty == Tdelegate)
- {
- dg = (TypeDelegate *)t1;
- tf = (TypeFunction *)dg->next;
- }
- else if (t1->ty == Tfunction)
- tf = (TypeFunction *)t1;
- else
- return;
-
- if (e->arguments && e->arguments->length)
- {
- /* j=1 if _arguments[] is first argument,
- * skip it because it is not passed by ref
- */
- size_t j = tf->isDstyleVariadic();
- for (size_t i = j; i < e->arguments->length; ++i)
- {
- Expression *arg = (*e->arguments)[i];
- size_t nparams = tf->parameterList.length();
- if (i - j < nparams && i >= j)
- {
- Parameter *p = tf->parameterList[i - j];
- const StorageClass stc = tf->parameterStorageClass(p);
- if ((stc & (STCscope)) && (stc & STCreturn))
- arg->accept(this);
- else if ((stc & (STCref)) && (stc & STCreturn))
- escapeByRef(arg, er);
- }
- }
- }
- // If 'this' is returned, check it too
- if (e->e1->op == TOKdotvar && t1->ty == Tfunction)
- {
- DotVarExp *dve = (DotVarExp *)e->e1;
- FuncDeclaration *fd = dve->var->isFuncDeclaration();
- AggregateDeclaration *ad = NULL;
- if (global.params.vsafe && tf->isreturn && fd && (ad = fd->isThis()) != NULL)
- {
- if (ad->isClassDeclaration() || tf->isscope) // this is 'return scope'
- dve->e1->accept(this);
- else if (ad->isStructDeclaration()) // this is 'return ref'
- escapeByRef(dve->e1, er);
- }
- else if (dve->var->storage_class & STCreturn || tf->isreturn)
- {
- if (dve->var->storage_class & STCscope)
- dve->e1->accept(this);
- else if (dve->var->storage_class & STCref)
- escapeByRef(dve->e1, er);
- }
- }
-
- /* If returning the result of a delegate call, the .ptr
- * field of the delegate must be checked.
- */
- if (dg)
- {
- if (tf->isreturn)
- e->e1->accept(this);
- }
- }
- };
-
- EscapeVisitor v(er);
- e->accept(&v);
-}
-
-/****************************************
- * e is an expression to be returned by 'ref'.
- * Walk e to determine which variables are possibly being
- * returned by ref, such as:
- * ref int function(int i) { return i; }
- * If e is a form of *p, determine which variables have content
- * which is being returned as ref, such as:
- * ref int function(int* p) { return *p; }
- * Multiple variables can be inserted, because of expressions like this:
- * ref int function(bool b, int i, int* p) { return b ? i : *p; }
- *
- * No side effects.
- *
- * Params:
- * e = expression to be returned by 'ref'
- * er = where to place collected data
- */
-static void escapeByRef(Expression *e, EscapeByResults *er)
-{
- //printf("[%s] escapeByRef, e: %s\n", e->loc->toChars(), e->toChars());
- class EscapeRefVisitor : public Visitor
- {
- public:
- EscapeByResults *er;
-
- EscapeRefVisitor(EscapeByResults *er)
- : er(er)
- {
- }
-
- void visit(Expression *)
- {
- }
-
- void visit(VarExp *e)
- {
- VarDeclaration *v = e->var->isVarDeclaration();
- if (v)
- {
- if (v->storage_class & STCref && v->storage_class & (STCforeach | STCtemp) && v->_init)
- {
- /* If compiler generated ref temporary
- * (ref v = ex; ex)
- * look at the initializer instead
- */
- if (ExpInitializer *ez = v->_init->isExpInitializer())
- {
- assert(ez->exp && ez->exp->op == TOKconstruct);
- Expression *ex = ((ConstructExp *)ez->exp)->e2;
- ex->accept(this);
- }
- }
- else
- er->byref.push(v);
- }
- }
-
- void visit(ThisExp *e)
- {
- if (e->var)
- er->byref.push(e->var);
- }
-
- void visit(PtrExp *e)
- {
- escapeByValue(e->e1, er);
- }
-
- void visit(IndexExp *e)
- {
- Type *tb = e->e1->type->toBasetype();
- if (e->e1->op == TOKvar)
- {
- VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (v->storage_class & STCvariadic)
- {
- er->byref.push(v);
- return;
- }
- }
- }
- if (tb->ty == Tsarray)
- {
- e->e1->accept(this);
- }
- else if (tb->ty == Tarray)
- {
- escapeByValue(e->e1, er);
- }
- }
-
- void visit(DotVarExp *e)
- {
- Type *t1b = e->e1->type->toBasetype();
- if (t1b->ty == Tclass)
- escapeByValue(e->e1, er);
- else
- e->e1->accept(this);
- }
-
- void visit(BinAssignExp *e)
- {
- e->e1->accept(this);
- }
-
- void visit(AssignExp *e)
- {
- e->e1->accept(this);
- }
-
- void visit(CommaExp *e)
- {
- e->e2->accept(this);
- }
-
- void visit(CondExp *e)
- {
- e->e1->accept(this);
- e->e2->accept(this);
- }
-
- void visit(CallExp *e)
- {
- /* If the function returns by ref, check each argument that is
- * passed as 'return ref'.
- */
- Type *t1 = e->e1->type->toBasetype();
- TypeFunction *tf;
- if (t1->ty == Tdelegate)
- tf = (TypeFunction *)((TypeDelegate *)t1)->next;
- else if (t1->ty == Tfunction)
- tf = (TypeFunction *)t1;
- else
- return;
- if (tf->isref)
- {
- if (e->arguments && e->arguments->length)
- {
- /* j=1 if _arguments[] is first argument,
- * skip it because it is not passed by ref
- */
- size_t j = tf->isDstyleVariadic();
-
- for (size_t i = j; i < e->arguments->length; ++i)
- {
- Expression *arg = (*e->arguments)[i];
- size_t nparams = tf->parameterList.length();
- if (i - j < nparams && i >= j)
- {
- Parameter *p = tf->parameterList[i - j];
- const StorageClass stc = tf->parameterStorageClass(p);
- if ((stc & (STCout | STCref)) && (stc & STCreturn))
- arg->accept(this);
- else if ((stc & STCscope) && (stc & STCreturn))
- {
- if (arg->op == TOKdelegate)
- {
- DelegateExp *de = (DelegateExp *)arg;
- if (de->func->isNested())
- er->byexp.push(de);
- }
- else
- escapeByValue(arg, er);
- }
- }
- }
- }
-
- // If 'this' is returned by ref, check it too
- if (e->e1->op == TOKdotvar && t1->ty == Tfunction)
- {
- DotVarExp *dve = (DotVarExp *)e->e1;
- if (dve->var->storage_class & STCreturn || tf->isreturn)
- {
- if ((dve->var->storage_class & STCscope) || tf->isscope)
- escapeByValue(dve->e1, er);
- else if ((dve->var->storage_class & STCref) || tf->isref)
- dve->e1->accept(this);
- }
-
- }
- // If it's a delegate, check it too
- if (e->e1->op == TOKvar && t1->ty == Tdelegate)
- {
- escapeByValue(e->e1, er);
- }
- }
- else
- er->byexp.push(e);
- }
- };
-
- EscapeRefVisitor v(er);
- e->accept(&v);
-}
-
-/*************************
- * Find all variables accessed by this delegate that are
- * in functions enclosing it.
- * Params:
- * fd = function
- * vars = array to append found variables to
- */
-void findAllOuterAccessedVariables(FuncDeclaration *fd, VarDeclarations *vars)
-{
- //printf("findAllOuterAccessedVariables(fd: %s)\n", fd.toChars());
- for (Dsymbol *p = fd->parent; p; p = p->parent)
- {
- FuncDeclaration *fdp = p->isFuncDeclaration();
- if (fdp)
- {
- for (size_t i = 0; i < fdp->closureVars.length; i++)
- {
- VarDeclaration *v = fdp->closureVars[i];
- for (size_t j = 0; j < v->nestedrefs.length; j++)
- {
- FuncDeclaration *fdv = v->nestedrefs[j];
- if (fdv == fd)
- {
- //printf("accessed: %s, type %s\n", v->toChars(), v->type->toChars());
- vars->push(v);
- }
- }
- }
- }
- }
-}