diff --git a/dmd2/declaration.h b/dmd2/declaration.h index 8eda9412..190382b7 100644 --- a/dmd2/declaration.h +++ b/dmd2/declaration.h @@ -914,11 +914,6 @@ public: /// Codegen traversal void codegen(IRState* ir); - // vars declared in this function that nested funcs reference - // is this is not empty, nestedFrameRef is set and these VarDecls - // probably have nestedref set too, see VarDeclaration::checkNestedReference - std::set nestedVars; - std::string intrinsicName; uint32_t priority; diff --git a/driver/main.cpp b/driver/main.cpp index 9c6c913e..47320d4f 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -570,14 +570,17 @@ static void registerPredefinedTargetVersions() { VersionCondition::addPredefinedGlobalIdent("Cygwin"); break; case llvm::Triple::Linux: - VersionCondition::addPredefinedGlobalIdent("linux"); - VersionCondition::addPredefinedGlobalIdent("Posix"); #if LDC_LLVM_VER >= 302 if (global.params.targetTriple.getEnvironment() == llvm::Triple::Android) { VersionCondition::addPredefinedGlobalIdent("Android"); } + else #endif + { + VersionCondition::addPredefinedGlobalIdent("linux"); + VersionCondition::addPredefinedGlobalIdent("Posix"); + } break; case llvm::Triple::Haiku: VersionCondition::addPredefinedGlobalIdent("Haiku"); @@ -622,8 +625,6 @@ static void registerPredefinedTargetVersions() { #if LDC_LLVM_VER >= 302 case llvm::Triple::Android: VersionCondition::addPredefinedGlobalIdent("Android"); - VersionCondition::addPredefinedGlobalIdent("linux"); - VersionCondition::addPredefinedGlobalIdent("Posix"); break; #endif default: diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 99309520..54df6b63 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -576,14 +576,6 @@ DValue* DtoCastInt(Loc& loc, DValue* val, Type* _to) return new DImValue(_to, rval); } - // Check for special DMD hack to avoid "has no effect" error. - // See expression.c, method AssignExp::semantic(), around line 11499 - llvm::ConstantInt* isConstInt = isaConstantInt(rval); - if (from == Type::tint32 && to == Type::tvoid && isConstInt->isNullValue()) - { - return val; - } - size_t fromsz = from->size(); size_t tosz = to->size(); diff --git a/gen/nested.cpp b/gen/nested.cpp index 41d5ad12..15608876 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -15,6 +15,7 @@ #include "gen/llvmhelpers.h" #include "gen/logger.h" #include "gen/tollvm.h" +#include "gen/utils.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Support/CommandLine.h" namespace cl = llvm::cl; @@ -223,7 +224,7 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) return llvm::ConstantPointerNull::get(getVoidPtrType()); } - struct FuncDeclaration* frameToPass = 0; + FuncDeclaration* frameToPass = 0; if (AggregateDeclaration *ad = sym->isAggregateDeclaration()) { // If sym is a nested struct or a nested class, pass the frame // of the function where sym is declared. @@ -285,17 +286,8 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) { return; fd->ir.irFunc->nestedContextCreated = true; - // fill nestedVars - assert(fd->nestedVars.empty() && "nestedVars should only be filled here"); - size_t nnest = fd->closureVars.dim; - for (size_t i = 0; i < nnest; ++i) - { - VarDeclaration* vd = static_cast(fd->closureVars.data[i]); - fd->nestedVars.insert(vd); - } - // construct nested variables array - if (!fd->nestedVars.empty()) + if (fd->closureVars.dim != 0) { Logger::println("has nested frame"); // start with adding all enclosing parent frames until a static parent is reached @@ -345,9 +337,9 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) { // Add the direct nested variables of this function, and update their indices to match. // TODO: optimize ordering for minimal space usage? - for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) - { - VarDeclaration* vd = *i; + VarDeclarationIter closureVarsIter(fd->closureVars); + for (; closureVarsIter.more(); closureVarsIter.next()) { + VarDeclaration* vd = *closureVarsIter; if (!vd->ir.irLocal) vd->ir.irLocal = new IrLocal(vd); @@ -404,7 +396,7 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { DtoCreateNestedContextType(fd); // construct nested variables array - if (!fd->nestedVars.empty()) + if (fd->closureVars.dim != 0) { IrFunction* irfunction = fd->ir.irFunc; unsigned depth = irfunction->depth; @@ -451,9 +443,9 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { irfunction->nestedVar = frame; // go through all nested vars and assign addresses where possible. - for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) - { - VarDeclaration* vd = *i; + VarDeclarationIter closureVarsIter(fd->closureVars); + for (; closureVarsIter.more(); closureVarsIter.next()) { + VarDeclaration* vd = *closureVarsIter; LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); if (vd->isParameter()) { diff --git a/gen/runtime.cpp b/gen/runtime.cpp index 3a9d73c4..66f26b73 100644 --- a/gen/runtime.cpp +++ b/gen/runtime.cpp @@ -168,6 +168,18 @@ static LLType* rt_dg2() return LLStructType::get(gIR->context(), types, false); } +template +static void ensureDecl(DECL *decl, const char *msg) +{ + if (!decl || !decl->type) + { + Logger::println("Missing class declaration: %s\n", msg); + error(Loc(), "Missing class declaration: %s", msg); + errorSupplemental(Loc(), "Please check that object.di is included and valid"); + fatal(); + } +} + static void LLVM_D_BuildRuntimeModule() { Logger::println("building runtime module"); @@ -187,10 +199,15 @@ static void LLVM_D_BuildRuntimeModule() LLType* wstringTy = DtoType(Type::twchar->arrayOf()); LLType* dstringTy = DtoType(Type::tdchar->arrayOf()); + ensureDecl(ClassDeclaration::object, "Object"); LLType* objectTy = DtoType(ClassDeclaration::object->type); + ensureDecl(Type::typeinfoclass, "TypeInfo_Class"); LLType* classInfoTy = DtoType(Type::typeinfoclass->type); + ensureDecl(Type::dtypeinfo, "DTypeInfo"); LLType* typeInfoTy = DtoType(Type::dtypeinfo->type); + ensureDecl(Type::typeinfoassociativearray, "TypeInfo_AssociativeArray"); LLType* aaTypeInfoTy = DtoType(Type::typeinfoassociativearray->type); + ensureDecl(Module::moduleinfo, "ModuleInfo"); LLType* moduleInfoPtrTy = getPtrToType(DtoType(Module::moduleinfo->type)); LLType* aaTy = rt_ptr(LLStructType::get(gIR->context())); diff --git a/gen/toir.cpp b/gen/toir.cpp index 537d5495..777ab052 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -520,6 +520,7 @@ DValue* AssignExp::toElem(IRState* p) if (se->lwr == NULL && ta->ty == Tsarray && e2->op == TOKarrayliteral && + op == TOKconstruct && // DMD Bugzilla 11238: avoid aliasing issue t2->nextOf()->mutableOf()->implicitConvTo(ta->nextOf())) { ArrayLiteralExp * const ale = static_cast(e2); @@ -1140,13 +1141,9 @@ DValue* CastExp::toElem(IRState* p) // get the value to cast DValue* u = e1->toElem(p); - // a constructor expression is casted to void in order to mark - // the value as unused. See expression.d, method AssignExp::semantic(), - // around line 11681 - if (to == Type::tvoid && e1->op == TOKconstruct) - { - return new DNullValue(Type::tvoid, 0); - } + // handle cast to void (usually created by frontend to avoid "has no effect" error) + if (to == Type::tvoid) + return new DImValue(Type::tvoid, llvm::UndefValue::get(voidToI8(DtoType(Type::tvoid)))); // cast it to the 'to' type, if necessary DValue* v = u; @@ -2294,7 +2291,7 @@ DValue* AssertExp::toElem(IRState* p) // call assert runtime functions p->scope() = IRScope(assertbb,endbb); - DtoAssert(p->func()->decl->getModule(), loc, msg ? msg->toElem(p) : NULL); + DtoAssert(p->func()->decl->getModule(), loc, msg ? msg->toElemDtor(p) : NULL); // rewrite the scope p->scope() = IRScope(endbb,oldend); @@ -3184,9 +3181,7 @@ DValue* ClassReferenceExp::toElem(IRState* p) toChars(), type->toChars()); LOG_SCOPE; - error("ClassReferenceExp::toElem is not yet implemented"); - fatal(); - return 0; + return new DImValue(type, toConstElem(p)); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -3261,21 +3256,23 @@ llvm::Constant* ClassReferenceExp::toConstElem(IRState *p) llvm::Constant* result = value->globalVar; - assert(type->ty == Tclass); - ClassDeclaration* targetClass = static_cast(type)->sym; - if (InterfaceDeclaration* it = targetClass->isInterfaceDeclaration()) { - assert(it->isBaseOf(origClass, NULL)); + if (type->ty == Tclass) { + ClassDeclaration* targetClass = static_cast(type)->sym; + if (InterfaceDeclaration* it = targetClass->isInterfaceDeclaration()) { + assert(it->isBaseOf(origClass, NULL)); - IrTypeClass* typeclass = origClass->type->irtype->isClass(); + IrTypeClass* typeclass = origClass->type->irtype->isClass(); - // find interface impl - size_t i_index = typeclass->getInterfaceIndex(it); - assert(i_index != ~0UL); + // find interface impl + size_t i_index = typeclass->getInterfaceIndex(it); + assert(i_index != ~0UL); - // offset pointer - result = DtoGEPi(result, 0, i_index); + // offset pointer + result = DtoGEPi(result, 0, i_index); + } } + assert(type->ty == Tclass || type->ty == Tenum); return DtoBitCast(result, DtoType(type)); } diff --git a/gen/typinf.cpp b/gen/typinf.cpp index cbe7e00d..3695c789 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -109,6 +109,11 @@ Expression *Type::getInternalTypeInfo(Scope *sc) return t->getTypeInfo(sc); } + +bool inNonRoot(Dsymbol *s); +FuncDeclaration *search_toHash(StructDeclaration *sd); +FuncDeclaration *search_toString(StructDeclaration *sd); + /**************************************************** * Get the exact TypeInfo. */ @@ -146,9 +151,23 @@ Expression *Type::getTypeInfo(Scope *sc) if (!t->builtinTypeInfo()) { // Generate COMDAT if (sc) // if in semantic() pass - { // Find module that will go all the way to an object file + { + // Find module that will go all the way to an object file Module *m = sc->module->importedFrom; m->members->push(t->vtinfo); + + if (ty == Tstruct) + { + StructDeclaration *sd = ((TypeStruct *)this)->sym; + if ((sd->xeq && sd->xeq != sd->xerreq || + sd->xcmp && sd->xcmp != sd->xerrcmp || + search_toHash(sd) || + search_toString(sd) + ) && inNonRoot(sd)) + { + Module::addDeferredSemantic3(sd); + } + } } else // if in obj generation pass { @@ -572,21 +591,6 @@ void TypeInfoDelegateDeclaration::llvmDefine() /* ========================================================================= */ -static FuncDeclaration* find_method_overload(AggregateDeclaration* ad, Identifier* id, TypeFunction* tf) -{ - Dsymbol *s = search_function(ad, id); - FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; - if (fdx) - { - FuncDeclaration *fd = fdx->overloadExactMatch(tf); - if (fd) - { - return fd; - } - } - return NULL; -} - void TypeInfoStructDeclaration::llvmDefine() { Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", toChars()); @@ -597,6 +601,13 @@ void TypeInfoStructDeclaration::llvmDefine() TypeStruct *tc = static_cast(tinfo); StructDeclaration *sd = tc->sym; + // handle opaque structs + if (!sd->members) { + RTTIBuilder b(Type::typeinfostruct); + b.finalize(ir.irGlobal); + return; + } + // can't emit typeinfo for forward declarations if (sd->sizeok != SIZEOKdone) { @@ -622,41 +633,10 @@ void TypeInfoStructDeclaration::llvmDefine() initPtr = iraggr->getInitSymbol(); b.push_void_array(getTypeStoreSize(DtoType(tc)), initPtr); - // toX functions ground work - static TypeFunction *tftohash; - static TypeFunction *tftostring; - - if (!tftohash) - { - Scope sc; - tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); - tftohash ->mod = MODconst; - tftohash = static_cast(tftohash->semantic(Loc(), &sc)); - - Type *retType = Type::tchar->immutableOf()->arrayOf(); - tftostring = new TypeFunction(NULL, retType, 0, LINKd); - tftostring = static_cast(tftostring->semantic(Loc(), &sc)); - } - - // this one takes a parameter, so we need to build a new one each time - // to get the right type. can we avoid this? - TypeFunction *tfcmpptr; - { - Scope sc; - Parameters *arguments = new Parameters; - - // arg type is ref const T - Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); - arguments->push(arg); - tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); - tfcmpptr->mod = MODconst; - tfcmpptr = static_cast(tfcmpptr->semantic(Loc(), &sc)); - } - // well use this module for all overload lookups // toHash - FuncDeclaration* fd = find_method_overload(sd, Id::tohash, tftohash); + FuncDeclaration* fd = search_toHash(sd); b.push_funcptr(fd); // opEquals @@ -664,11 +644,11 @@ void TypeInfoStructDeclaration::llvmDefine() b.push_funcptr(fd); // opCmp - fd = find_method_overload(sd, Id::cmp, tfcmpptr); + fd = sd->xcmp; b.push_funcptr(fd); // toString - fd = find_method_overload(sd, Id::tostring, tftostring); + fd = search_toString(sd); b.push_funcptr(fd); // uint m_flags; diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index b5133480..683784a5 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -89,6 +89,7 @@ if(APPLE) endif() file(GLOB_RECURSE CORE_D_UNIX ${RUNTIME_DIR}/src/core/sys/posix/*.d) file(GLOB_RECURSE CORE_D_FREEBSD ${RUNTIME_DIR}/src/core/sys/freebsd/*.d) +file(GLOB_RECURSE CORE_D_LINUX ${RUNTIME_DIR}/src/core/sys/linux/*.d) file(GLOB_RECURSE CORE_D_OSX ${RUNTIME_DIR}/src/core/sys/osx/*.d) file(GLOB_RECURSE CORE_D_WIN ${RUNTIME_DIR}/src/core/sys/windows/*.d) set(CORE_D_SYS) @@ -98,7 +99,21 @@ if(UNIX) if(${CMAKE_SYSTEM} MATCHES "FreeBSD") list(APPEND CORE_D_SYS ${CORE_D_FREEBSD}) endif() - list(APPEND DCRT_ASM ${RUNTIME_DIR}/src/core/threadasm.S) + if(${CMAKE_SYSTEM} MATCHES "Linux") + list(APPEND CORE_D_SYS ${CORE_D_LINUX}) + endif() + # Assembler support was rewritten in CMake 2.8.5. + # The assembler file must be passed to gcc but prior to this + # version it is passed to as. This results in a bunch of + # error message. This is only critical for non-x86 platforms. + # On x86/x86-64 the file can safely be ignored. + if("${CMAKE_VERSION}" MATCHES "^2\\.8\\.[01234]($|\\..*)") + message(WARNING "Excluding core/threadasm.S from build because of missing CMake support.") + message(WARNING "This file is required for certain non-x86 platforms.") + message(WARNING "Please consider updating CMake to at least 2.8.5.") + else() + list(APPEND DCRT_ASM ${RUNTIME_DIR}/src/core/threadasm.S) + endif() if(APPLE) list(APPEND CORE_D_SYS ${CORE_D_OSX}) endif()