mirror of git://gcc.gnu.org/git/gcc.git
Give an error if a label is defined but not used.
From-SVN: r171518
This commit is contained in:
parent
de5ca9cf78
commit
fb4347e44d
|
@ -1463,6 +1463,7 @@ class Check_types_traverse : public Traverse
|
||||||
Check_types_traverse(Gogo* gogo)
|
Check_types_traverse(Gogo* gogo)
|
||||||
: Traverse(traverse_variables
|
: Traverse(traverse_variables
|
||||||
| traverse_constants
|
| traverse_constants
|
||||||
|
| traverse_functions
|
||||||
| traverse_statements
|
| traverse_statements
|
||||||
| traverse_expressions),
|
| traverse_expressions),
|
||||||
gogo_(gogo)
|
gogo_(gogo)
|
||||||
|
@ -1474,6 +1475,9 @@ class Check_types_traverse : public Traverse
|
||||||
int
|
int
|
||||||
constant(Named_object*, bool);
|
constant(Named_object*, bool);
|
||||||
|
|
||||||
|
int
|
||||||
|
function(Named_object*);
|
||||||
|
|
||||||
int
|
int
|
||||||
statement(Block*, size_t* pindex, Statement*);
|
statement(Block*, size_t* pindex, Statement*);
|
||||||
|
|
||||||
|
@ -1542,6 +1546,16 @@ Check_types_traverse::constant(Named_object* named_object, bool)
|
||||||
return TRAVERSE_CONTINUE;
|
return TRAVERSE_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// There are no types to check in a function, but this is where we
|
||||||
|
// issue warnings about labels which are defined but not referenced.
|
||||||
|
|
||||||
|
int
|
||||||
|
Check_types_traverse::function(Named_object* no)
|
||||||
|
{
|
||||||
|
no->func_value()->check_labels();
|
||||||
|
return TRAVERSE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
// Check that types are valid in a statement.
|
// Check that types are valid in a statement.
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -2744,7 +2758,7 @@ Function::add_label_definition(const std::string& label_name,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error_at(location, "redefinition of label %qs",
|
error_at(location, "label %qs already defined",
|
||||||
Gogo::message_name(label_name).c_str());
|
Gogo::message_name(label_name).c_str());
|
||||||
inform(label->location(), "previous definition of %qs was here",
|
inform(label->location(), "previous definition of %qs was here",
|
||||||
Gogo::message_name(label_name).c_str());
|
Gogo::message_name(label_name).c_str());
|
||||||
|
@ -2764,17 +2778,36 @@ Function::add_label_reference(const std::string& label_name)
|
||||||
if (!ins.second)
|
if (!ins.second)
|
||||||
{
|
{
|
||||||
// The label was already in the hash table.
|
// The label was already in the hash table.
|
||||||
return ins.first->second;
|
Label* label = ins.first->second;
|
||||||
|
label->set_is_used();
|
||||||
|
return label;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gcc_assert(ins.first->second == NULL);
|
gcc_assert(ins.first->second == NULL);
|
||||||
Label* label = new Label(label_name);
|
Label* label = new Label(label_name);
|
||||||
ins.first->second = label;
|
ins.first->second = label;
|
||||||
|
label->set_is_used();
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Warn about labels that are defined but not used.
|
||||||
|
|
||||||
|
void
|
||||||
|
Function::check_labels() const
|
||||||
|
{
|
||||||
|
for (Labels::const_iterator p = this->labels_.begin();
|
||||||
|
p != this->labels_.end();
|
||||||
|
p++)
|
||||||
|
{
|
||||||
|
Label* label = p->second;
|
||||||
|
if (!label->is_used())
|
||||||
|
error_at(label->location(), "label %qs defined and not used",
|
||||||
|
Gogo::message_name(label->name()).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Swap one function with another. This is used when building the
|
// Swap one function with another. This is used when building the
|
||||||
// thunk we use to call a function which calls recover. It may not
|
// thunk we use to call a function which calls recover. It may not
|
||||||
// work for any other case.
|
// work for any other case.
|
||||||
|
|
|
@ -882,6 +882,10 @@ class Function
|
||||||
Label*
|
Label*
|
||||||
add_label_reference(const std::string& label_name);
|
add_label_reference(const std::string& label_name);
|
||||||
|
|
||||||
|
// Warn about labels that are defined but not used.
|
||||||
|
void
|
||||||
|
check_labels() const;
|
||||||
|
|
||||||
// Whether this function calls the predeclared recover function.
|
// Whether this function calls the predeclared recover function.
|
||||||
bool
|
bool
|
||||||
calls_recover() const
|
calls_recover() const
|
||||||
|
@ -2090,7 +2094,7 @@ class Label
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Label(const std::string& name)
|
Label(const std::string& name)
|
||||||
: name_(name), location_(0), decl_(NULL)
|
: name_(name), location_(0), is_used_(false), decl_(NULL)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
// Return the label's name.
|
// Return the label's name.
|
||||||
|
@ -2103,6 +2107,16 @@ class Label
|
||||||
is_defined() const
|
is_defined() const
|
||||||
{ return this->location_ != 0; }
|
{ return this->location_ != 0; }
|
||||||
|
|
||||||
|
// Return whether the label has been used.
|
||||||
|
bool
|
||||||
|
is_used() const
|
||||||
|
{ return this->is_used_; }
|
||||||
|
|
||||||
|
// Record that the label is used.
|
||||||
|
void
|
||||||
|
set_is_used()
|
||||||
|
{ this->is_used_ = true; }
|
||||||
|
|
||||||
// Return the location of the definition.
|
// Return the location of the definition.
|
||||||
source_location
|
source_location
|
||||||
location() const
|
location() const
|
||||||
|
@ -2130,6 +2144,8 @@ class Label
|
||||||
// The location of the definition. This is 0 if the label has not
|
// The location of the definition. This is 0 if the label has not
|
||||||
// yet been defined.
|
// yet been defined.
|
||||||
source_location location_;
|
source_location location_;
|
||||||
|
// Whether the label has been used.
|
||||||
|
bool is_used_;
|
||||||
// The LABEL_DECL.
|
// The LABEL_DECL.
|
||||||
tree decl_;
|
tree decl_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -3112,7 +3112,7 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
|
||||||
// LABEL is the label of this statement if it has one.
|
// LABEL is the label of this statement if it has one.
|
||||||
|
|
||||||
void
|
void
|
||||||
Parse::statement(const Label* label)
|
Parse::statement(Label* label)
|
||||||
{
|
{
|
||||||
const Token* token = this->peek_token();
|
const Token* token = this->peek_token();
|
||||||
switch (token->classification())
|
switch (token->classification())
|
||||||
|
@ -3288,6 +3288,10 @@ Parse::labeled_stmt(const std::string& label_name, source_location location)
|
||||||
|
|
||||||
if (!this->statement_may_start_here())
|
if (!this->statement_may_start_here())
|
||||||
{
|
{
|
||||||
|
// Mark the label as used to avoid a useless error about an
|
||||||
|
// unused label.
|
||||||
|
label->set_is_used();
|
||||||
|
|
||||||
error_at(location, "missing statement after label");
|
error_at(location, "missing statement after label");
|
||||||
this->unget_token(Token::make_operator_token(OPERATOR_SEMICOLON,
|
this->unget_token(Token::make_operator_token(OPERATOR_SEMICOLON,
|
||||||
location));
|
location));
|
||||||
|
@ -3774,7 +3778,7 @@ Parse::if_stat()
|
||||||
// TypeSwitchGuard = [ identifier ":=" ] Expression "." "(" "type" ")" .
|
// TypeSwitchGuard = [ identifier ":=" ] Expression "." "(" "type" ")" .
|
||||||
|
|
||||||
void
|
void
|
||||||
Parse::switch_stat(const Label* label)
|
Parse::switch_stat(Label* label)
|
||||||
{
|
{
|
||||||
gcc_assert(this->peek_token()->is_keyword(KEYWORD_SWITCH));
|
gcc_assert(this->peek_token()->is_keyword(KEYWORD_SWITCH));
|
||||||
source_location location = this->location();
|
source_location location = this->location();
|
||||||
|
@ -3873,7 +3877,7 @@ Parse::switch_stat(const Label* label)
|
||||||
// "{" { ExprCaseClause } "}"
|
// "{" { ExprCaseClause } "}"
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Parse::expr_switch_body(const Label* label, Expression* switch_val,
|
Parse::expr_switch_body(Label* label, Expression* switch_val,
|
||||||
source_location location)
|
source_location location)
|
||||||
{
|
{
|
||||||
Switch_statement* statement = Statement::make_switch_statement(switch_val,
|
Switch_statement* statement = Statement::make_switch_statement(switch_val,
|
||||||
|
@ -3983,7 +3987,7 @@ Parse::expr_switch_case(bool* is_default)
|
||||||
// "{" { TypeCaseClause } "}" .
|
// "{" { TypeCaseClause } "}" .
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
Parse::type_switch_body(const Label* label, const Type_switch& type_switch,
|
Parse::type_switch_body(Label* label, const Type_switch& type_switch,
|
||||||
source_location location)
|
source_location location)
|
||||||
{
|
{
|
||||||
Named_object* switch_no = NULL;
|
Named_object* switch_no = NULL;
|
||||||
|
@ -4127,7 +4131,7 @@ Parse::type_switch_case(std::vector<Type*>* types, bool* is_default)
|
||||||
// SelectStat = "select" "{" { CommClause } "}" .
|
// SelectStat = "select" "{" { CommClause } "}" .
|
||||||
|
|
||||||
void
|
void
|
||||||
Parse::select_stat(const Label* label)
|
Parse::select_stat(Label* label)
|
||||||
{
|
{
|
||||||
gcc_assert(this->peek_token()->is_keyword(KEYWORD_SELECT));
|
gcc_assert(this->peek_token()->is_keyword(KEYWORD_SELECT));
|
||||||
source_location location = this->location();
|
source_location location = this->location();
|
||||||
|
@ -4435,7 +4439,7 @@ Parse::send_or_recv_stmt(bool* is_send, Expression** channel, Expression** val,
|
||||||
// Condition = Expression .
|
// Condition = Expression .
|
||||||
|
|
||||||
void
|
void
|
||||||
Parse::for_stat(const Label* label)
|
Parse::for_stat(Label* label)
|
||||||
{
|
{
|
||||||
gcc_assert(this->peek_token()->is_keyword(KEYWORD_FOR));
|
gcc_assert(this->peek_token()->is_keyword(KEYWORD_FOR));
|
||||||
source_location location = this->location();
|
source_location location = this->location();
|
||||||
|
@ -4654,7 +4658,7 @@ Parse::range_clause_expr(const Expression_list* vals,
|
||||||
// Push a statement on the break stack.
|
// Push a statement on the break stack.
|
||||||
|
|
||||||
void
|
void
|
||||||
Parse::push_break_statement(Statement* enclosing, const Label* label)
|
Parse::push_break_statement(Statement* enclosing, Label* label)
|
||||||
{
|
{
|
||||||
if (this->break_stack_ == NULL)
|
if (this->break_stack_ == NULL)
|
||||||
this->break_stack_ = new Bc_stack();
|
this->break_stack_ = new Bc_stack();
|
||||||
|
@ -4664,7 +4668,7 @@ Parse::push_break_statement(Statement* enclosing, const Label* label)
|
||||||
// Push a statement on the continue stack.
|
// Push a statement on the continue stack.
|
||||||
|
|
||||||
void
|
void
|
||||||
Parse::push_continue_statement(Statement* enclosing, const Label* label)
|
Parse::push_continue_statement(Statement* enclosing, Label* label)
|
||||||
{
|
{
|
||||||
if (this->continue_stack_ == NULL)
|
if (this->continue_stack_ == NULL)
|
||||||
this->continue_stack_ = new Bc_stack();
|
this->continue_stack_ = new Bc_stack();
|
||||||
|
@ -4697,8 +4701,13 @@ Parse::find_bc_statement(const Bc_stack* bc_stack, const std::string& label)
|
||||||
for (Bc_stack::const_reverse_iterator p = bc_stack->rbegin();
|
for (Bc_stack::const_reverse_iterator p = bc_stack->rbegin();
|
||||||
p != bc_stack->rend();
|
p != bc_stack->rend();
|
||||||
++p)
|
++p)
|
||||||
if (p->second != NULL && p->second->name() == label)
|
{
|
||||||
return p->first;
|
if (p->second != NULL && p->second->name() == label)
|
||||||
|
{
|
||||||
|
p->second->set_is_used();
|
||||||
|
return p->first;
|
||||||
|
}
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4728,9 +4737,11 @@ Parse::break_stat()
|
||||||
token->identifier());
|
token->identifier());
|
||||||
if (enclosing == NULL)
|
if (enclosing == NULL)
|
||||||
{
|
{
|
||||||
error_at(token->location(),
|
// If there is a label with this name, mark it as used to
|
||||||
("break label %qs not associated with "
|
// avoid a useless error about an unused label.
|
||||||
"for or switch or select"),
|
this->gogo_->add_label_reference(token->identifier());
|
||||||
|
|
||||||
|
error_at(token->location(), "invalid break label %qs",
|
||||||
Gogo::message_name(token->identifier()).c_str());
|
Gogo::message_name(token->identifier()).c_str());
|
||||||
this->advance_token();
|
this->advance_token();
|
||||||
return;
|
return;
|
||||||
|
@ -4781,8 +4792,11 @@ Parse::continue_stat()
|
||||||
token->identifier());
|
token->identifier());
|
||||||
if (enclosing == NULL)
|
if (enclosing == NULL)
|
||||||
{
|
{
|
||||||
error_at(token->location(),
|
// If there is a label with this name, mark it as used to
|
||||||
"continue label %qs not associated with for",
|
// avoid a useless error about an unused label.
|
||||||
|
this->gogo_->add_label_reference(token->identifier());
|
||||||
|
|
||||||
|
error_at(token->location(), "invalid continue label %qs",
|
||||||
Gogo::message_name(token->identifier()).c_str());
|
Gogo::message_name(token->identifier()).c_str());
|
||||||
this->advance_token();
|
this->advance_token();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -150,7 +150,7 @@ class Parse
|
||||||
// For break and continue we keep a stack of statements with
|
// For break and continue we keep a stack of statements with
|
||||||
// associated labels (if any). The top of the stack is used for a
|
// associated labels (if any). The top of the stack is used for a
|
||||||
// break or continue statement with no label.
|
// break or continue statement with no label.
|
||||||
typedef std::vector<std::pair<Statement*, const Label*> > Bc_stack;
|
typedef std::vector<std::pair<Statement*, Label*> > Bc_stack;
|
||||||
|
|
||||||
// Parser nonterminals.
|
// Parser nonterminals.
|
||||||
void identifier_list(Typed_identifier_list*);
|
void identifier_list(Typed_identifier_list*);
|
||||||
|
@ -220,7 +220,7 @@ class Parse
|
||||||
bool* is_type_switch);
|
bool* is_type_switch);
|
||||||
Expression* qualified_expr(Expression*, source_location);
|
Expression* qualified_expr(Expression*, source_location);
|
||||||
Expression* id_to_expression(const std::string&, source_location);
|
Expression* id_to_expression(const std::string&, source_location);
|
||||||
void statement(const Label*);
|
void statement(Label*);
|
||||||
bool statement_may_start_here();
|
bool statement_may_start_here();
|
||||||
void labeled_stmt(const std::string&, source_location);
|
void labeled_stmt(const std::string&, source_location);
|
||||||
Expression* simple_stat(bool, bool, Range_clause*, Type_switch*);
|
Expression* simple_stat(bool, bool, Range_clause*, Type_switch*);
|
||||||
|
@ -236,26 +236,25 @@ class Parse
|
||||||
void go_or_defer_stat();
|
void go_or_defer_stat();
|
||||||
void return_stat();
|
void return_stat();
|
||||||
void if_stat();
|
void if_stat();
|
||||||
void switch_stat(const Label*);
|
void switch_stat(Label*);
|
||||||
Statement* expr_switch_body(const Label*, Expression*, source_location);
|
Statement* expr_switch_body(Label*, Expression*, source_location);
|
||||||
void expr_case_clause(Case_clauses*, bool* saw_default);
|
void expr_case_clause(Case_clauses*, bool* saw_default);
|
||||||
Expression_list* expr_switch_case(bool*);
|
Expression_list* expr_switch_case(bool*);
|
||||||
Statement* type_switch_body(const Label*, const Type_switch&,
|
Statement* type_switch_body(Label*, const Type_switch&, source_location);
|
||||||
source_location);
|
|
||||||
void type_case_clause(Named_object*, Type_case_clauses*, bool* saw_default);
|
void type_case_clause(Named_object*, Type_case_clauses*, bool* saw_default);
|
||||||
void type_switch_case(std::vector<Type*>*, bool*);
|
void type_switch_case(std::vector<Type*>*, bool*);
|
||||||
void select_stat(const Label*);
|
void select_stat(Label*);
|
||||||
void comm_clause(Select_clauses*, bool* saw_default);
|
void comm_clause(Select_clauses*, bool* saw_default);
|
||||||
bool comm_case(bool*, Expression**, Expression**, Expression**,
|
bool comm_case(bool*, Expression**, Expression**, Expression**,
|
||||||
std::string*, std::string*, bool*);
|
std::string*, std::string*, bool*);
|
||||||
bool send_or_recv_stmt(bool*, Expression**, Expression**, Expression**,
|
bool send_or_recv_stmt(bool*, Expression**, Expression**, Expression**,
|
||||||
std::string*, std::string*);
|
std::string*, std::string*);
|
||||||
void for_stat(const Label*);
|
void for_stat(Label*);
|
||||||
void for_clause(Expression**, Block**);
|
void for_clause(Expression**, Block**);
|
||||||
void range_clause_decl(const Typed_identifier_list*, Range_clause*);
|
void range_clause_decl(const Typed_identifier_list*, Range_clause*);
|
||||||
void range_clause_expr(const Expression_list*, Range_clause*);
|
void range_clause_expr(const Expression_list*, Range_clause*);
|
||||||
void push_break_statement(Statement*, const Label*);
|
void push_break_statement(Statement*, Label*);
|
||||||
void push_continue_statement(Statement*, const Label*);
|
void push_continue_statement(Statement*, Label*);
|
||||||
void pop_break_statement();
|
void pop_break_statement();
|
||||||
void pop_continue_statement();
|
void pop_continue_statement();
|
||||||
Statement* find_bc_statement(const Bc_stack*, const std::string&);
|
Statement* find_bc_statement(const Bc_stack*, const std::string&);
|
||||||
|
|
|
@ -7,16 +7,21 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var i int;
|
var i int
|
||||||
var j int;
|
var j int
|
||||||
if true {}
|
if true {
|
||||||
{ return }
|
}
|
||||||
i = 0;
|
{
|
||||||
if true {} else i++;
|
return
|
||||||
type s struct {};
|
}
|
||||||
i = 0;
|
i = 0
|
||||||
type s2 int;
|
if true {
|
||||||
var k = func (a int) int { return a+1 }(3);
|
} else {
|
||||||
_, _ = j, k;
|
i++
|
||||||
ro: ;
|
}
|
||||||
|
type s struct{}
|
||||||
|
i = 0
|
||||||
|
type s2 int
|
||||||
|
var k = func(a int) int { return a + 1 }(3)
|
||||||
|
_, _ = j, k
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// $G $D/$F.go && $L $F.$A && ./$A.out
|
// $G $D/$F.go && $L $F.$A
|
||||||
|
|
||||||
// Copyright 2009 The Go Authors. All rights reserved.
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
|
@ -7,12 +7,16 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
func f() {
|
func f() {
|
||||||
exit: ;
|
exit:
|
||||||
|
;
|
||||||
|
goto exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
exit: ; // this should be legal (labels not properly scoped?)
|
exit:
|
||||||
|
; // this should be legal (labels not properly scoped?)
|
||||||
|
goto exit
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var exit int;
|
var exit int
|
||||||
exit:
|
exit:
|
||||||
_ = exit;
|
_ = exit
|
||||||
|
goto exit
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,18 +7,19 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
func f1() {
|
func f1() {
|
||||||
exit:
|
exit:
|
||||||
print("hi\n");
|
print("hi\n")
|
||||||
|
goto exit
|
||||||
}
|
}
|
||||||
|
|
||||||
func f2() {
|
func f2() {
|
||||||
const c = 1234;
|
const c = 1234
|
||||||
}
|
}
|
||||||
|
|
||||||
func f3() {
|
func f3() {
|
||||||
i := c; // ERROR "undef"
|
i := c // ERROR "undef"
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
f3();
|
f3()
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,16 +8,21 @@ package main
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
L1:
|
L1:
|
||||||
L2: for i := 0; i < 10; i++ {
|
L2:
|
||||||
print(i);
|
for i := 0; i < 10; i++ {
|
||||||
break L2;
|
print(i)
|
||||||
|
break L2
|
||||||
}
|
}
|
||||||
|
|
||||||
L3: ;
|
L3:
|
||||||
L4: for i := 0; i < 10; i++ {
|
;
|
||||||
print(i);
|
L4:
|
||||||
break L4;
|
for i := 0; i < 10; i++ {
|
||||||
|
print(i)
|
||||||
|
break L4
|
||||||
}
|
}
|
||||||
|
goto L1
|
||||||
|
goto L3
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -7,8 +7,17 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if true {} else L1: ;
|
if true {
|
||||||
if true {} else L2: main() ;
|
} else {
|
||||||
|
L1:
|
||||||
|
}
|
||||||
|
if true {
|
||||||
|
} else {
|
||||||
|
L2:
|
||||||
|
main()
|
||||||
|
}
|
||||||
|
goto L1
|
||||||
|
goto L2
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -9,19 +9,25 @@ package main
|
||||||
func main() {
|
func main() {
|
||||||
L:
|
L:
|
||||||
for i := 0; i < 1; i++ {
|
for i := 0; i < 1; i++ {
|
||||||
L1:
|
L1:
|
||||||
for {
|
for {
|
||||||
break L;
|
break L
|
||||||
}
|
}
|
||||||
panic("BUG: not reached - break");
|
panic("BUG: not reached - break")
|
||||||
}
|
}
|
||||||
|
|
||||||
L2:
|
L2:
|
||||||
for i := 0; i < 1; i++ {
|
for i := 0; i < 1; i++ {
|
||||||
L3:
|
L3:
|
||||||
for {
|
for {
|
||||||
continue L2;
|
continue L2
|
||||||
}
|
}
|
||||||
panic("BUG: not reached - continue");
|
panic("BUG: not reached - continue")
|
||||||
|
}
|
||||||
|
if false {
|
||||||
|
goto L1
|
||||||
|
}
|
||||||
|
if false {
|
||||||
|
goto L3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,16 +10,18 @@ func main() {
|
||||||
L:
|
L:
|
||||||
for {
|
for {
|
||||||
for {
|
for {
|
||||||
break L2; // ERROR "L2"
|
break L2 // ERROR "L2"
|
||||||
continue L2; // ERROR "L2"
|
continue L2 // ERROR "L2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
L1:
|
L1:
|
||||||
x := 1;
|
x := 1
|
||||||
_ = x;
|
_ = x
|
||||||
for {
|
for {
|
||||||
break L1; // ERROR "L1"
|
break L1 // ERROR "L1"
|
||||||
continue L1; // ERROR "L1"
|
continue L1 // ERROR "L1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goto L
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ func main() {
|
||||||
case 1:
|
case 1:
|
||||||
L1: // ERROR "statement"
|
L1: // ERROR "statement"
|
||||||
default:
|
default:
|
||||||
L2: // correct since no semicolon is required before a '}'
|
// correct since no semicolon is required before a '}'
|
||||||
|
L2: // GCCGO_ERROR "not used"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue