diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 564abdc1..85cd44d8 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -184,10 +184,10 @@ void DtoGoto(Loc* loc, Identifier* target, EnclosingHandler* enclosinghandler) // if the target label is inside inline asm, error if(lblstmt->asmLabel) - error("cannot goto into inline asm block", loc->toChars()); + error(*loc, "cannot goto into inline asm block"); // find target basic block - std::string labelname = target->toChars(); + std::string labelname = gIR->func()->getScopedLabelName(target->toChars()); llvm::BasicBlock*& targetBB = gIR->func()->labelToBB[labelname]; if (targetBB == NULL) targetBB = llvm::BasicBlock::Create("label", gIR->topfunc()); @@ -200,7 +200,12 @@ void DtoGoto(Loc* loc, Identifier* target, EnclosingHandler* enclosinghandler) // error if didn't find tf statement of label if(endfinally != lblstmt->enclosinghandler) - error("cannot goto into try block", loc->toChars()); + error(*loc, "cannot goto into try block"); + + // goto into finally blocks is forbidden by the spec + // though it should not be problematic to implement + if(lblstmt->tf) + error(*loc, "spec disallows goto into finally block"); // emit code for finallys between goto and label DtoEnclosingHandlers(enclosinghandler, endfinally); @@ -263,12 +268,20 @@ void DtoEnclosingHandlers(EnclosingHandler* start, EnclosingHandler* end) } assert(endfinally == end); + + // // emit code for finallys between start and end + // + + // since the labelstatements possibly inside are private + // and might already exist push a label scope + gIR->func()->pushUniqueLabelScope("enclosing"); EnclosingHandler* tf = start; while(tf != end) { tf->emitCode(gIR); tf = tf->getEnclosing(); } + gIR->func()->popLabelScope(); } /****************************************************************************************/ diff --git a/gen/statements.cpp b/gen/statements.cpp index 56e30415..7cd3fd86 100644 --- a/gen/statements.cpp +++ b/gen/statements.cpp @@ -1033,7 +1033,7 @@ void LabelStatement::toIR(IRState* p) } else { - std::string labelname = ident->toChars(); + std::string labelname = p->func()->getScopedLabelName(ident->toChars()); llvm::BasicBlock*& labelBB = p->func()->labelToBB[labelname]; llvm::BasicBlock* oldend = gIR->scopeend(); diff --git a/ir/irfunction.cpp b/ir/irfunction.cpp index 08a34616..4a670140 100644 --- a/ir/irfunction.cpp +++ b/ir/irfunction.cpp @@ -3,6 +3,8 @@ #include "gen/tollvm.h" #include "ir/irfunction.h" +#include + ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -29,4 +31,31 @@ IrFunction::IrFunction(FuncDeclaration* fd) srcfileArg = NULL; msgArg = NULL; + + nextUnique.push(0); +} + +std::string IrFunction::getScopedLabelName(const char* ident) +{ + if(labelScopes.empty()) + return std::string(ident); + + std::string result = "__"; + for(unsigned int i = 0; i < labelScopes.size(); ++i) + result += labelScopes[i] + "_"; + return result + ident; +} + +void IrFunction::pushUniqueLabelScope(const char* name) +{ + std::ostringstream uniquename; + uniquename << name << nextUnique.top()++; + nextUnique.push(0); + labelScopes.push_back(uniquename.str()); +} + +void IrFunction::popLabelScope() +{ + labelScopes.pop_back(); + nextUnique.pop(); } diff --git a/ir/irfunction.h b/ir/irfunction.h index ac98ad97..594296e8 100644 --- a/ir/irfunction.h +++ b/ir/irfunction.h @@ -5,6 +5,8 @@ #include "ir/irlandingpad.h" #include +#include +#include // represents a function struct IrFunction : IrBase @@ -26,6 +28,16 @@ struct IrFunction : IrBase llvm::AllocaInst* srcfileArg; llvm::AllocaInst* msgArg; + // pushes a unique label scope of the given name + void pushUniqueLabelScope(const char* name); + // pops a label scope + void popLabelScope(); + + // gets the string under which the label's BB + // is stored in the labelToBB map. + // essentially prefixes ident by the strings in labelScopes + std::string getScopedLabelName(const char* ident); + // label to basic block lookup typedef std::map LabelToBBMap; LabelToBBMap labelToBB; @@ -34,6 +46,14 @@ struct IrFunction : IrBase IRLandingPad landingPad; IrFunction(FuncDeclaration* fd); + +private: + // prefix for labels and gotos + // used for allowing labels to be emitted twice + std::vector labelScopes; + + // next unique id stack + std::stack nextUnique; }; #endif diff --git a/ir/irlandingpad.cpp b/ir/irlandingpad.cpp index 281eef41..c9c9c9d9 100644 --- a/ir/irlandingpad.cpp +++ b/ir/irlandingpad.cpp @@ -150,7 +150,12 @@ void IRLandingPad::constructLandingPad(llvm::BasicBlock* inBB) { if(switchinst) switchinst = NULL; + + // since this may be emitted multiple times + // give the labels a new scope + gIR->func()->pushUniqueLabelScope("finally"); it->finallyBody->toIR(gIR); + gIR->func()->popLabelScope(); } // otherwise it's a catch and we'll add a switch case else