#include "dmd/aggregate.h"
#include "dmd/attrib.h"
+#include "dmd/cond.h"
#include "dmd/ctfe.h"
#include "dmd/declaration.h"
#include "dmd/enum.h"
{
using Visitor::visit;
+ /* If we're lowering the body of a version(unittest) condition. */
+ bool in_version_unittest_;
+
public:
DeclVisitor (void)
{
+ this->in_version_unittest_ = false;
}
/* This should be overridden by each declaration class. */
visit ((AttribDeclaration *) d);
}
+ /* Conditional compilation is the process of selecting which code to compile
+ and which code to not compile. Look for version conditions that may */
+
+ void visit (ConditionalDeclaration *d)
+ {
+ bool old_condition = this->in_version_unittest_;
+
+ if (global.params.useUnitTests)
+ {
+ VersionCondition *vc = d->condition->isVersionCondition ();
+ if (vc && vc->ident == Identifier::idPool ("unittest"))
+ this->in_version_unittest_ = true;
+ }
+
+ visit ((AttribDeclaration *) d);
+
+ this->in_version_unittest_ = old_condition;
+ }
+
/* Walk over all members in the namespace scope. */
void visit (Nspace *d)
}
DECL_ARGUMENTS (fndecl) = param_list;
+ DECL_IN_UNITTEST_CONDITION_P (fndecl) = this->in_version_unittest_;
rest_of_decl_compilation (fndecl, 1, 0);
/* If this is a member function that nested (possibly indirectly) in another
static module_info *current_moduleinfo;
+/* When compiling with -fbuilding-libphobos-tests, this contains information
+ about the module that gets compiled in only when unittests are enabled. */
+
+static module_info *current_testing_module;
+
/* The declaration of the current module being compiled. */
static Module *current_module_decl;
assert (!current_moduleinfo && !current_module_decl);
module_info mi = module_info ();
+ module_info mitest = module_info ();
current_moduleinfo = &mi;
+ current_testing_module = &mitest;
current_module_decl = decl;
/* Layout module members. */
}
}
+ /* For libphobos-internal use only. Generate a separate module info symbol
+ that references all compiled in unittests, this allows compiling library
+ modules and linking to libphobos without having run-time conflicts because
+ of two ModuleInfo records with the same name being present in two DSOs. */
+ if (flag_building_libphobos_tests)
+ {
+ /* Associate the module info symbol with a mock module. */
+ const char *name = concat (GDC_PREFIX ("modtest__"),
+ decl->ident->toChars (), NULL);
+ Module *tm = Module::create (decl->arg, Identifier::idPool (name), 0, 0);
+ Dsymbols members;
+
+ /* Setting parent puts module in the same package as the current, to
+ avoid any symbol conflicts. */
+ tm->parent = decl->parent;
+ tm->needmoduleinfo = decl->needmoduleinfo;
+ tm->members = &members;
+ /* Register the current module as being imported by the mock module.
+ This informs run-time that there is a dependency between the two. */
+ tm->aimports.push (decl);
+
+ if (mitest.ctors || mitest.ctorgates)
+ tm->sctor = build_funcs_gates_fn (get_identifier ("*__modtestctor"),
+ mitest.ctors, mitest.ctorgates);
+
+ if (mitest.dtors)
+ tm->sdtor = build_funcs_gates_fn (get_identifier ("*__modtestdtor"),
+ mitest.dtors, NULL);
+
+ if (mitest.sharedctors || mitest.sharedctorgates)
+ tm->ssharedctor
+ = build_funcs_gates_fn (get_identifier ("*__modtestsharedctor"),
+ mitest.sharedctors, mitest.sharedctorgates);
+
+ if (mitest.shareddtors)
+ tm->sshareddtor
+ = build_funcs_gates_fn (get_identifier ("*__modtestshareddtor"),
+ mitest.shareddtors, NULL);
+
+ if (mi.unitTests)
+ tm->stest = build_funcs_gates_fn (get_identifier ("*__modtest"),
+ mi.unitTests, NULL);
+
+ mi.unitTests = NULL;
+ layout_moduleinfo (tm);
+ }
+
/* Default behavior is to always generate module info because of templates.
Can be switched off for not compiling against runtime library. */
if (!global.params.betterC
}
current_moduleinfo = NULL;
+ current_testing_module = NULL;
current_module_decl = NULL;
}
{
tree decl = get_symbol_decl (fd);
+ /* Any module constructors or destructors that are only present when
+ compiling in unittests are kept track of separately so they are
+ not omitted when compiling with -fbuilding-libphobos-tests. */
+ module_info *minfo;
+ if (flag_building_libphobos_tests && DECL_IN_UNITTEST_CONDITION_P (decl))
+ minfo = current_testing_module;
+ else
+ minfo = current_moduleinfo;
+
+ gcc_assert (minfo != NULL);
+
/* If a static constructor, push into the current ModuleInfo.
Checks for `shared' first because it derives from the non-shared
constructor type in the front-end. */
if (fd->isSharedStaticCtorDeclaration ())
- vec_safe_push (current_moduleinfo->sharedctors, decl);
+ vec_safe_push (minfo->sharedctors, decl);
else if (fd->isStaticCtorDeclaration ())
- vec_safe_push (current_moduleinfo->ctors, decl);
+ vec_safe_push (minfo->ctors, decl);
/* If a static destructor, do same as with constructors, but also
increment the destructor's vgate at construction time. */
if (vgate != NULL)
{
tree gate = get_symbol_decl (vgate);
- vec_safe_push (current_moduleinfo->sharedctorgates, gate);
+ vec_safe_push (minfo->sharedctorgates, gate);
}
- vec_safe_insert (current_moduleinfo->shareddtors, 0, decl);
+ vec_safe_insert (minfo->shareddtors, 0, decl);
}
else if (fd->isStaticDtorDeclaration ())
{
if (vgate != NULL)
{
tree gate = get_symbol_decl (vgate);
- vec_safe_push (current_moduleinfo->ctorgates, gate);
+ vec_safe_push (minfo->ctorgates, gate);
}
- vec_safe_insert (current_moduleinfo->dtors, 0, decl);
+ vec_safe_insert (minfo->dtors, 0, decl);
}
/* If a unittest function. */
if (fd->isUnitTestDeclaration ())
- vec_safe_push (current_moduleinfo->unitTests, decl);
+ vec_safe_push (minfo->unitTests, decl);
}
}