diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-09-20 21:00:07 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-09-20 21:00:07 +0000 |
commit | 6675c41604f61f041d894413b2daabe177fa57a9 (patch) | |
tree | ef020738a977887d068fec88173fa59aff82bb42 /gcc/go/gofrontend/gogo.cc | |
parent | b432106bc016fe9f794a71629274244b94d1dfe0 (diff) | |
download | gcc-6675c41604f61f041d894413b2daabe177fa57a9.zip gcc-6675c41604f61f041d894413b2daabe177fa57a9.tar.gz gcc-6675c41604f61f041d894413b2daabe177fa57a9.tar.bz2 |
Implement goto restrictions.
From-SVN: r179018
Diffstat (limited to 'gcc/go/gofrontend/gogo.cc')
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 168 |
1 files changed, 147 insertions, 21 deletions
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index be7592b..9df9402 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -857,7 +857,7 @@ Gogo::add_label_definition(const std::string& label_name, { go_assert(!this->functions_.empty()); Function* func = this->functions_.back().function->func_value(); - Label* label = func->add_label_definition(label_name, location); + Label* label = func->add_label_definition(this, label_name, location); this->add_statement(Statement::make_label_statement(label, location)); return label; } @@ -865,11 +865,21 @@ Gogo::add_label_definition(const std::string& label_name, // Add a label reference. Label* -Gogo::add_label_reference(const std::string& label_name) +Gogo::add_label_reference(const std::string& label_name, + source_location location, bool issue_goto_errors) { go_assert(!this->functions_.empty()); Function* func = this->functions_.back().function->func_value(); - return func->add_label_reference(label_name); + return func->add_label_reference(this, label_name, location, + issue_goto_errors); +} + +// Return the current binding state. + +Bindings_snapshot* +Gogo::bindings_snapshot(source_location location) +{ + return new Bindings_snapshot(this->current_block(), location); } // Add a statement. @@ -2843,30 +2853,24 @@ Function::is_method() const // Add a label definition. Label* -Function::add_label_definition(const std::string& label_name, +Function::add_label_definition(Gogo* gogo, const std::string& label_name, source_location location) { Label* lnull = NULL; std::pair<Labels::iterator, bool> ins = this->labels_.insert(std::make_pair(label_name, lnull)); + Label* label; if (ins.second) { // This is a new label. - Label* label = new Label(label_name); - label->define(location); + label = new Label(label_name); ins.first->second = label; - return label; } else { // The label was already in the hash table. - Label* label = ins.first->second; - if (!label->is_defined()) - { - label->define(location); - return label; - } - else + label = ins.first->second; + if (label->is_defined()) { error_at(location, "label %qs already defined", Gogo::message_name(label_name).c_str()); @@ -2875,31 +2879,55 @@ Function::add_label_definition(const std::string& label_name, return new Label(label_name); } } + + label->define(location, gogo->bindings_snapshot(location)); + + // Issue any errors appropriate for any previous goto's to this + // label. + const std::vector<Bindings_snapshot*>& refs(label->refs()); + for (std::vector<Bindings_snapshot*>::const_iterator p = refs.begin(); + p != refs.end(); + ++p) + (*p)->check_goto_to(gogo->current_block()); + label->clear_refs(); + + return label; } // Add a reference to a label. Label* -Function::add_label_reference(const std::string& label_name) +Function::add_label_reference(Gogo* gogo, const std::string& label_name, + source_location location, bool issue_goto_errors) { Label* lnull = NULL; std::pair<Labels::iterator, bool> ins = this->labels_.insert(std::make_pair(label_name, lnull)); + Label* label; if (!ins.second) { // The label was already in the hash table. - Label* label = ins.first->second; - label->set_is_used(); - return label; + label = ins.first->second; } else { go_assert(ins.first->second == NULL); - Label* label = new Label(label_name); + label = new Label(label_name); ins.first->second = label; - label->set_is_used(); - return label; } + + label->set_is_used(); + + if (issue_goto_errors) + { + Bindings_snapshot* snapshot = label->snapshot(); + if (snapshot != NULL) + snapshot->check_goto_from(gogo->current_block(), location); + else + label->add_snapshot_ref(gogo->bindings_snapshot(location)); + } + + return label; } // Warn about labels that are defined but not used. @@ -3407,6 +3435,92 @@ Block::get_backend(Translate_context* context) return ret; } +// Class Bindings_snapshot. + +Bindings_snapshot::Bindings_snapshot(const Block* b, source_location location) + : block_(b), counts_(), location_(location) +{ + while (b != NULL) + { + this->counts_.push_back(b->bindings()->size_definitions()); + b = b->enclosing(); + } +} + +// Report errors appropriate for a goto from B to this. + +void +Bindings_snapshot::check_goto_from(const Block* b, source_location loc) +{ + size_t dummy; + if (!this->check_goto_block(loc, b, this->block_, &dummy)) + return; + this->check_goto_defs(loc, this->block_, + this->block_->bindings()->size_definitions(), + this->counts_[0]); +} + +// Report errors appropriate for a goto from this to B. + +void +Bindings_snapshot::check_goto_to(const Block* b) +{ + size_t index; + if (!this->check_goto_block(this->location_, this->block_, b, &index)) + return; + this->check_goto_defs(this->location_, b, this->counts_[index], + b->bindings()->size_definitions()); +} + +// Report errors appropriate for a goto at LOC from BFROM to BTO. +// Return true if all is well, false if we reported an error. If this +// returns true, it sets *PINDEX to the number of blocks BTO is above +// BFROM. + +bool +Bindings_snapshot::check_goto_block(source_location loc, const Block* bfrom, + const Block* bto, size_t* pindex) +{ + // It is an error if BTO is not either BFROM or above BFROM. + size_t index = 0; + for (const Block* pb = bfrom; pb != bto; pb = pb->enclosing(), ++index) + { + if (pb == NULL) + { + error_at(loc, "goto jumps into block"); + inform(bto->start_location(), "goto target block starts here"); + return false; + } + } + *pindex = index; + return true; +} + +// Report errors appropriate for a goto at LOC ending at BLOCK, where +// CFROM is the number of names defined at the point of the goto and +// CTO is the number of names defined at the point of the label. + +void +Bindings_snapshot::check_goto_defs(source_location loc, const Block* block, + size_t cfrom, size_t cto) +{ + if (cfrom < cto) + { + Bindings::const_definitions_iterator p = + block->bindings()->begin_definitions(); + for (size_t i = 0; i < cfrom; ++i) + { + go_assert(p != block->bindings()->end_definitions()); + ++p; + } + go_assert(p != block->bindings()->end_definitions()); + + std::string n = (*p)->message_name(); + error_at(loc, "goto jumps over declaration of %qs", n.c_str()); + inform((*p)->location(), "%qs defined here", n.c_str()); + } +} + // Class Variable. Variable::Variable(Type* type, Expression* init, bool is_global, @@ -4698,6 +4812,18 @@ Bindings::traverse(Traverse* traverse, bool is_global) // Class Label. +// Clear any references to this label. + +void +Label::clear_refs() +{ + for (std::vector<Bindings_snapshot*>::iterator p = this->refs_.begin(); + p != this->refs_.end(); + ++p) + delete *p; + this->refs_.clear(); +} + // Get the backend representation for a label. Blabel* |