OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [go/] [gofrontend/] [statements.cc] - Blame information for rev 801

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 714 jeremybenn
// statements.cc -- Go frontend statements.
2
 
3
// Copyright 2009 The Go Authors. All rights reserved.
4
// Use of this source code is governed by a BSD-style
5
// license that can be found in the LICENSE file.
6
 
7
#include "go-system.h"
8
 
9
#include <gmp.h>
10
 
11
#include "go-c.h"
12
#include "types.h"
13
#include "expressions.h"
14
#include "gogo.h"
15
#include "runtime.h"
16
#include "backend.h"
17
#include "statements.h"
18
#include "ast-dump.h"
19
 
20
// Class Statement.
21
 
22
Statement::Statement(Statement_classification classification,
23
                     Location location)
24
  : classification_(classification), location_(location)
25
{
26
}
27
 
28
Statement::~Statement()
29
{
30
}
31
 
32
// Traverse the tree.  The work of walking the components is handled
33
// by the subclasses.
34
 
35
int
36
Statement::traverse(Block* block, size_t* pindex, Traverse* traverse)
37
{
38
  if (this->classification_ == STATEMENT_ERROR)
39
    return TRAVERSE_CONTINUE;
40
 
41
  unsigned int traverse_mask = traverse->traverse_mask();
42
 
43
  if ((traverse_mask & Traverse::traverse_statements) != 0)
44
    {
45
      int t = traverse->statement(block, pindex, this);
46
      if (t == TRAVERSE_EXIT)
47
        return TRAVERSE_EXIT;
48
      else if (t == TRAVERSE_SKIP_COMPONENTS)
49
        return TRAVERSE_CONTINUE;
50
    }
51
 
52
  // No point in checking traverse_mask here--a statement may contain
53
  // other blocks or statements, and if we got here we always want to
54
  // walk them.
55
  return this->do_traverse(traverse);
56
}
57
 
58
// Traverse the contents of a statement.
59
 
60
int
61
Statement::traverse_contents(Traverse* traverse)
62
{
63
  return this->do_traverse(traverse);
64
}
65
 
66
// Traverse assignments.
67
 
68
bool
69
Statement::traverse_assignments(Traverse_assignments* tassign)
70
{
71
  if (this->classification_ == STATEMENT_ERROR)
72
    return false;
73
  return this->do_traverse_assignments(tassign);
74
}
75
 
76
// Traverse an expression in a statement.  This is a helper function
77
// for child classes.
78
 
79
int
80
Statement::traverse_expression(Traverse* traverse, Expression** expr)
81
{
82
  if ((traverse->traverse_mask()
83
       & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
84
    return TRAVERSE_CONTINUE;
85
  return Expression::traverse(expr, traverse);
86
}
87
 
88
// Traverse an expression list in a statement.  This is a helper
89
// function for child classes.
90
 
91
int
92
Statement::traverse_expression_list(Traverse* traverse,
93
                                    Expression_list* expr_list)
94
{
95
  if (expr_list == NULL)
96
    return TRAVERSE_CONTINUE;
97
  if ((traverse->traverse_mask()
98
       & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
99
    return TRAVERSE_CONTINUE;
100
  return expr_list->traverse(traverse);
101
}
102
 
103
// Traverse a type in a statement.  This is a helper function for
104
// child classes.
105
 
106
int
107
Statement::traverse_type(Traverse* traverse, Type* type)
108
{
109
  if ((traverse->traverse_mask()
110
       & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
111
    return TRAVERSE_CONTINUE;
112
  return Type::traverse(type, traverse);
113
}
114
 
115
// Set type information for unnamed constants.  This is really done by
116
// the child class.
117
 
118
void
119
Statement::determine_types()
120
{
121
  this->do_determine_types();
122
}
123
 
124
// If this is a thunk statement, return it.
125
 
126
Thunk_statement*
127
Statement::thunk_statement()
128
{
129
  Thunk_statement* ret = this->convert<Thunk_statement, STATEMENT_GO>();
130
  if (ret == NULL)
131
    ret = this->convert<Thunk_statement, STATEMENT_DEFER>();
132
  return ret;
133
}
134
 
135
// Convert a Statement to the backend representation.  This is really
136
// done by the child class.
137
 
138
Bstatement*
139
Statement::get_backend(Translate_context* context)
140
{
141
  if (this->classification_ == STATEMENT_ERROR)
142
    return context->backend()->error_statement();
143
  return this->do_get_backend(context);
144
}
145
 
146
// Dump AST representation for a statement to a dump context.
147
 
148
void
149
Statement::dump_statement(Ast_dump_context* ast_dump_context) const
150
{
151
  this->do_dump_statement(ast_dump_context);
152
}
153
 
154
// Note that this statement is erroneous.  This is called by children
155
// when they discover an error.
156
 
157
void
158
Statement::set_is_error()
159
{
160
  this->classification_ = STATEMENT_ERROR;
161
}
162
 
163
// For children to call to report an error conveniently.
164
 
165
void
166
Statement::report_error(const char* msg)
167
{
168
  error_at(this->location_, "%s", msg);
169
  this->set_is_error();
170
}
171
 
172
// An error statement, used to avoid crashing after we report an
173
// error.
174
 
175
class Error_statement : public Statement
176
{
177
 public:
178
  Error_statement(Location location)
179
    : Statement(STATEMENT_ERROR, location)
180
  { }
181
 
182
 protected:
183
  int
184
  do_traverse(Traverse*)
185
  { return TRAVERSE_CONTINUE; }
186
 
187
  Bstatement*
188
  do_get_backend(Translate_context*)
189
  { go_unreachable(); }
190
 
191
  void
192
  do_dump_statement(Ast_dump_context*) const;
193
};
194
 
195
// Dump the AST representation for an error statement.
196
 
197
void
198
Error_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
199
{
200
  ast_dump_context->print_indent();
201
  ast_dump_context->ostream() << "Error statement" << std::endl;
202
}
203
 
204
// Make an error statement.
205
 
206
Statement*
207
Statement::make_error_statement(Location location)
208
{
209
  return new Error_statement(location);
210
}
211
 
212
// Class Variable_declaration_statement.
213
 
214
Variable_declaration_statement::Variable_declaration_statement(
215
    Named_object* var)
216
  : Statement(STATEMENT_VARIABLE_DECLARATION, var->var_value()->location()),
217
    var_(var)
218
{
219
}
220
 
221
// We don't actually traverse the variable here; it was traversed
222
// while traversing the Block.
223
 
224
int
225
Variable_declaration_statement::do_traverse(Traverse*)
226
{
227
  return TRAVERSE_CONTINUE;
228
}
229
 
230
// Traverse the assignments in a variable declaration.  Note that this
231
// traversal is different from the usual traversal.
232
 
233
bool
234
Variable_declaration_statement::do_traverse_assignments(
235
    Traverse_assignments* tassign)
236
{
237
  tassign->initialize_variable(this->var_);
238
  return true;
239
}
240
 
241
// Lower the variable's initialization expression.
242
 
243
Statement*
244
Variable_declaration_statement::do_lower(Gogo* gogo, Named_object* function,
245
                                         Block*, Statement_inserter* inserter)
246
{
247
  this->var_->var_value()->lower_init_expression(gogo, function, inserter);
248
  return this;
249
}
250
 
251
// Convert a variable declaration to the backend representation.
252
 
253
Bstatement*
254
Variable_declaration_statement::do_get_backend(Translate_context* context)
255
{
256
  Variable* var = this->var_->var_value();
257
  Bvariable* bvar = this->var_->get_backend_variable(context->gogo(),
258
                                                     context->function());
259
  tree init = var->get_init_tree(context->gogo(), context->function());
260
  Bexpression* binit = init == NULL ? NULL : tree_to_expr(init);
261
 
262
  if (!var->is_in_heap())
263
    {
264
      go_assert(binit != NULL);
265
      return context->backend()->init_statement(bvar, binit);
266
    }
267
 
268
  // Something takes the address of this variable, so the value is
269
  // stored in the heap.  Initialize it to newly allocated memory
270
  // space, and assign the initial value to the new space.
271
  Location loc = this->location();
272
  Named_object* newfn = context->gogo()->lookup_global("new");
273
  go_assert(newfn != NULL && newfn->is_function_declaration());
274
  Expression* func = Expression::make_func_reference(newfn, NULL, loc);
275
  Expression_list* params = new Expression_list();
276
  params->push_back(Expression::make_type(var->type(), loc));
277
  Expression* call = Expression::make_call(func, params, false, loc);
278
  context->gogo()->lower_expression(context->function(), NULL, &call);
279
  Temporary_statement* temp = Statement::make_temporary(NULL, call, loc);
280
  Bstatement* btemp = temp->get_backend(context);
281
 
282
  Bstatement* set = NULL;
283
  if (binit != NULL)
284
    {
285
      Expression* e = Expression::make_temporary_reference(temp, loc);
286
      e = Expression::make_unary(OPERATOR_MULT, e, loc);
287
      Bexpression* be = tree_to_expr(e->get_tree(context));
288
      set = context->backend()->assignment_statement(be, binit, loc);
289
    }
290
 
291
  Expression* ref = Expression::make_temporary_reference(temp, loc);
292
  Bexpression* bref = tree_to_expr(ref->get_tree(context));
293
  Bstatement* sinit = context->backend()->init_statement(bvar, bref);
294
 
295
  std::vector<Bstatement*> stats;
296
  stats.reserve(3);
297
  stats.push_back(btemp);
298
  if (set != NULL)
299
    stats.push_back(set);
300
  stats.push_back(sinit);
301
  return context->backend()->statement_list(stats);
302
}
303
 
304
// Dump the AST representation for a variable declaration.
305
 
306
void
307
Variable_declaration_statement::do_dump_statement(
308
    Ast_dump_context* ast_dump_context) const
309
{
310
  ast_dump_context->print_indent();
311
 
312
  go_assert(var_->is_variable());
313
  ast_dump_context->ostream() << "var " << this->var_->name() <<  " ";
314
  Variable* var = this->var_->var_value();
315
  if (var->has_type())
316
    {
317
      ast_dump_context->dump_type(var->type());
318
      ast_dump_context->ostream() << " ";
319
    }
320
  if (var->init() != NULL)
321
    {
322
      ast_dump_context->ostream() <<  "= ";
323
      ast_dump_context->dump_expression(var->init());
324
    }
325
  ast_dump_context->ostream() << std::endl;
326
}
327
 
328
// Make a variable declaration.
329
 
330
Statement*
331
Statement::make_variable_declaration(Named_object* var)
332
{
333
  return new Variable_declaration_statement(var);
334
}
335
 
336
// Class Temporary_statement.
337
 
338
// Return the type of the temporary variable.
339
 
340
Type*
341
Temporary_statement::type() const
342
{
343
  return this->type_ != NULL ? this->type_ : this->init_->type();
344
}
345
 
346
// Traversal.
347
 
348
int
349
Temporary_statement::do_traverse(Traverse* traverse)
350
{
351
  if (this->type_ != NULL
352
      && this->traverse_type(traverse, this->type_) == TRAVERSE_EXIT)
353
    return TRAVERSE_EXIT;
354
  if (this->init_ == NULL)
355
    return TRAVERSE_CONTINUE;
356
  else
357
    return this->traverse_expression(traverse, &this->init_);
358
}
359
 
360
// Traverse assignments.
361
 
362
bool
363
Temporary_statement::do_traverse_assignments(Traverse_assignments* tassign)
364
{
365
  if (this->init_ == NULL)
366
    return false;
367
  tassign->value(&this->init_, true, true);
368
  return true;
369
}
370
 
371
// Determine types.
372
 
373
void
374
Temporary_statement::do_determine_types()
375
{
376
  if (this->type_ != NULL && this->type_->is_abstract())
377
    this->type_ = this->type_->make_non_abstract_type();
378
 
379
  if (this->init_ != NULL)
380
    {
381
      if (this->type_ == NULL)
382
        this->init_->determine_type_no_context();
383
      else
384
        {
385
          Type_context context(this->type_, false);
386
          this->init_->determine_type(&context);
387
        }
388
    }
389
 
390
  if (this->type_ == NULL)
391
    {
392
      this->type_ = this->init_->type();
393
      go_assert(!this->type_->is_abstract());
394
    }
395
}
396
 
397
// Check types.
398
 
399
void
400
Temporary_statement::do_check_types(Gogo*)
401
{
402
  if (this->type_ != NULL && this->init_ != NULL)
403
    {
404
      std::string reason;
405
      bool ok;
406
      if (this->are_hidden_fields_ok_)
407
        ok = Type::are_assignable_hidden_ok(this->type_, this->init_->type(),
408
                                            &reason);
409
      else
410
        ok = Type::are_assignable(this->type_, this->init_->type(), &reason);
411
      if (!ok)
412
        {
413
          if (reason.empty())
414
            error_at(this->location(), "incompatible types in assignment");
415
          else
416
            error_at(this->location(), "incompatible types in assignment (%s)",
417
                     reason.c_str());
418
          this->set_is_error();
419
        }
420
    }
421
}
422
 
423
// Convert to backend representation.
424
 
425
Bstatement*
426
Temporary_statement::do_get_backend(Translate_context* context)
427
{
428
  go_assert(this->bvariable_ == NULL);
429
 
430
  // FIXME: Permitting FUNCTION to be NULL here is a temporary measure
431
  // until we have a better representation of the init function.
432
  Named_object* function = context->function();
433
  Bfunction* bfunction;
434
  if (function == NULL)
435
    bfunction = NULL;
436
  else
437
    bfunction = tree_to_function(function->func_value()->get_decl());
438
 
439
  Btype* btype = this->type()->get_backend(context->gogo());
440
 
441
  Bexpression* binit;
442
  if (this->init_ == NULL)
443
    binit = NULL;
444
  else if (this->type_ == NULL)
445
    binit = tree_to_expr(this->init_->get_tree(context));
446
  else
447
    {
448
      Expression* init = Expression::make_cast(this->type_, this->init_,
449
                                               this->location());
450
      context->gogo()->lower_expression(context->function(), NULL, &init);
451
      binit = tree_to_expr(init->get_tree(context));
452
    }
453
 
454
  Bstatement* statement;
455
  this->bvariable_ =
456
    context->backend()->temporary_variable(bfunction, context->bblock(),
457
                                           btype, binit,
458
                                           this->is_address_taken_,
459
                                           this->location(), &statement);
460
  return statement;
461
}
462
 
463
// Return the backend variable.
464
 
465
Bvariable*
466
Temporary_statement::get_backend_variable(Translate_context* context) const
467
{
468
  if (this->bvariable_ == NULL)
469
    {
470
      go_assert(saw_errors());
471
      return context->backend()->error_variable();
472
    }
473
  return this->bvariable_;
474
}
475
 
476
// Dump the AST represemtation for a temporary statement
477
 
478
void
479
Temporary_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
480
{
481
  ast_dump_context->print_indent();
482
  ast_dump_context->dump_temp_variable_name(this);
483
  if (this->type_ != NULL)
484
    {
485
      ast_dump_context->ostream() << " ";
486
      ast_dump_context->dump_type(this->type_);
487
    }
488
  if (this->init_ != NULL)
489
    {
490
      ast_dump_context->ostream() << " = ";
491
      ast_dump_context->dump_expression(this->init_);
492
    }
493
  ast_dump_context->ostream() << std::endl;
494
}
495
 
496
// Make and initialize a temporary variable in BLOCK.
497
 
498
Temporary_statement*
499
Statement::make_temporary(Type* type, Expression* init,
500
                          Location location)
501
{
502
  return new Temporary_statement(type, init, location);
503
}
504
 
505
// An assignment statement.
506
 
507
class Assignment_statement : public Statement
508
{
509
 public:
510
  Assignment_statement(Expression* lhs, Expression* rhs,
511
                       Location location)
512
    : Statement(STATEMENT_ASSIGNMENT, location),
513
      lhs_(lhs), rhs_(rhs), are_hidden_fields_ok_(false)
514
  { }
515
 
516
  // Note that it is OK for this assignment statement to set hidden
517
  // fields.
518
  void
519
  set_hidden_fields_are_ok()
520
  { this->are_hidden_fields_ok_ = true; }
521
 
522
 protected:
523
  int
524
  do_traverse(Traverse* traverse);
525
 
526
  bool
527
  do_traverse_assignments(Traverse_assignments*);
528
 
529
  void
530
  do_determine_types();
531
 
532
  void
533
  do_check_types(Gogo*);
534
 
535
  Bstatement*
536
  do_get_backend(Translate_context*);
537
 
538
  void
539
  do_dump_statement(Ast_dump_context*) const;
540
 
541
 private:
542
  // Left hand side--the lvalue.
543
  Expression* lhs_;
544
  // Right hand side--the rvalue.
545
  Expression* rhs_;
546
  // True if this statement may set hidden fields in the assignment
547
  // statement.  This is used for generated method stubs.
548
  bool are_hidden_fields_ok_;
549
};
550
 
551
// Traversal.
552
 
553
int
554
Assignment_statement::do_traverse(Traverse* traverse)
555
{
556
  if (this->traverse_expression(traverse, &this->lhs_) == TRAVERSE_EXIT)
557
    return TRAVERSE_EXIT;
558
  return this->traverse_expression(traverse, &this->rhs_);
559
}
560
 
561
bool
562
Assignment_statement::do_traverse_assignments(Traverse_assignments* tassign)
563
{
564
  tassign->assignment(&this->lhs_, &this->rhs_);
565
  return true;
566
}
567
 
568
// Set types for the assignment.
569
 
570
void
571
Assignment_statement::do_determine_types()
572
{
573
  this->lhs_->determine_type_no_context();
574
  Type_context context(this->lhs_->type(), false);
575
  this->rhs_->determine_type(&context);
576
}
577
 
578
// Check types for an assignment.
579
 
580
void
581
Assignment_statement::do_check_types(Gogo*)
582
{
583
  // The left hand side must be either addressable, a map index
584
  // expression, or the blank identifier.
585
  if (!this->lhs_->is_addressable()
586
      && this->lhs_->map_index_expression() == NULL
587
      && !this->lhs_->is_sink_expression())
588
    {
589
      if (!this->lhs_->type()->is_error())
590
        this->report_error(_("invalid left hand side of assignment"));
591
      return;
592
    }
593
 
594
  Type* lhs_type = this->lhs_->type();
595
  Type* rhs_type = this->rhs_->type();
596
  std::string reason;
597
  bool ok;
598
  if (this->are_hidden_fields_ok_)
599
    ok = Type::are_assignable_hidden_ok(lhs_type, rhs_type, &reason);
600
  else
601
    ok = Type::are_assignable(lhs_type, rhs_type, &reason);
602
  if (!ok)
603
    {
604
      if (reason.empty())
605
        error_at(this->location(), "incompatible types in assignment");
606
      else
607
        error_at(this->location(), "incompatible types in assignment (%s)",
608
                 reason.c_str());
609
      this->set_is_error();
610
    }
611
 
612
  if (lhs_type->is_error() || rhs_type->is_error())
613
    this->set_is_error();
614
}
615
 
616
// Convert an assignment statement to the backend representation.
617
 
618
Bstatement*
619
Assignment_statement::do_get_backend(Translate_context* context)
620
{
621
  tree rhs_tree = this->rhs_->get_tree(context);
622
  if (this->lhs_->is_sink_expression())
623
    return context->backend()->expression_statement(tree_to_expr(rhs_tree));
624
  tree lhs_tree = this->lhs_->get_tree(context);
625
  rhs_tree = Expression::convert_for_assignment(context, this->lhs_->type(),
626
                                                this->rhs_->type(), rhs_tree,
627
                                                this->location());
628
  return context->backend()->assignment_statement(tree_to_expr(lhs_tree),
629
                                                  tree_to_expr(rhs_tree),
630
                                                  this->location());
631
}
632
 
633
// Dump the AST representation for an assignment statement.
634
 
635
void
636
Assignment_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
637
    const
638
{
639
  ast_dump_context->print_indent();
640
  ast_dump_context->dump_expression(this->lhs_);
641
  ast_dump_context->ostream() << " = " ;
642
  ast_dump_context->dump_expression(this->rhs_);
643
  ast_dump_context->ostream() << std::endl;
644
}
645
 
646
// Make an assignment statement.
647
 
648
Statement*
649
Statement::make_assignment(Expression* lhs, Expression* rhs,
650
                           Location location)
651
{
652
  return new Assignment_statement(lhs, rhs, location);
653
}
654
 
655
// The Move_subexpressions class is used to move all top-level
656
// subexpressions of an expression.  This is used for things like
657
// index expressions in which we must evaluate the index value before
658
// it can be changed by a multiple assignment.
659
 
660
class Move_subexpressions : public Traverse
661
{
662
 public:
663
  Move_subexpressions(int skip, Block* block)
664
    : Traverse(traverse_expressions),
665
      skip_(skip), block_(block)
666
  { }
667
 
668
 protected:
669
  int
670
  expression(Expression**);
671
 
672
 private:
673
  // The number of subexpressions to skip moving.  This is used to
674
  // avoid moving the array itself, as we only need to move the index.
675
  int skip_;
676
  // The block where new temporary variables should be added.
677
  Block* block_;
678
};
679
 
680
int
681
Move_subexpressions::expression(Expression** pexpr)
682
{
683
  if (this->skip_ > 0)
684
    --this->skip_;
685
  else if ((*pexpr)->temporary_reference_expression() == NULL)
686
    {
687
      Location loc = (*pexpr)->location();
688
      Temporary_statement* temp = Statement::make_temporary(NULL, *pexpr, loc);
689
      this->block_->add_statement(temp);
690
      *pexpr = Expression::make_temporary_reference(temp, loc);
691
    }
692
  // We only need to move top-level subexpressions.
693
  return TRAVERSE_SKIP_COMPONENTS;
694
}
695
 
696
// The Move_ordered_evals class is used to find any subexpressions of
697
// an expression that have an evaluation order dependency.  It creates
698
// temporary variables to hold them.
699
 
700
class Move_ordered_evals : public Traverse
701
{
702
 public:
703
  Move_ordered_evals(Block* block)
704
    : Traverse(traverse_expressions),
705
      block_(block)
706
  { }
707
 
708
 protected:
709
  int
710
  expression(Expression**);
711
 
712
 private:
713
  // The block where new temporary variables should be added.
714
  Block* block_;
715
};
716
 
717
int
718
Move_ordered_evals::expression(Expression** pexpr)
719
{
720
  // We have to look at subexpressions first.
721
  if ((*pexpr)->traverse_subexpressions(this) == TRAVERSE_EXIT)
722
    return TRAVERSE_EXIT;
723
 
724
  int i;
725
  if ((*pexpr)->must_eval_subexpressions_in_order(&i))
726
    {
727
      Move_subexpressions ms(i, this->block_);
728
      if ((*pexpr)->traverse_subexpressions(&ms) == TRAVERSE_EXIT)
729
        return TRAVERSE_EXIT;
730
    }
731
 
732
  if ((*pexpr)->must_eval_in_order())
733
    {
734
      Location loc = (*pexpr)->location();
735
      Temporary_statement* temp = Statement::make_temporary(NULL, *pexpr, loc);
736
      this->block_->add_statement(temp);
737
      *pexpr = Expression::make_temporary_reference(temp, loc);
738
    }
739
  return TRAVERSE_SKIP_COMPONENTS;
740
}
741
 
742
// An assignment operation statement.
743
 
744
class Assignment_operation_statement : public Statement
745
{
746
 public:
747
  Assignment_operation_statement(Operator op, Expression* lhs, Expression* rhs,
748
                                 Location location)
749
    : Statement(STATEMENT_ASSIGNMENT_OPERATION, location),
750
      op_(op), lhs_(lhs), rhs_(rhs)
751
  { }
752
 
753
 protected:
754
  int
755
  do_traverse(Traverse*);
756
 
757
  bool
758
  do_traverse_assignments(Traverse_assignments*)
759
  { go_unreachable(); }
760
 
761
  Statement*
762
  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
763
 
764
  Bstatement*
765
  do_get_backend(Translate_context*)
766
  { go_unreachable(); }
767
 
768
  void
769
  do_dump_statement(Ast_dump_context*) const;
770
 
771
 private:
772
  // The operator (OPERATOR_PLUSEQ, etc.).
773
  Operator op_;
774
  // Left hand side.
775
  Expression* lhs_;
776
  // Right hand side.
777
  Expression* rhs_;
778
};
779
 
780
// Traversal.
781
 
782
int
783
Assignment_operation_statement::do_traverse(Traverse* traverse)
784
{
785
  if (this->traverse_expression(traverse, &this->lhs_) == TRAVERSE_EXIT)
786
    return TRAVERSE_EXIT;
787
  return this->traverse_expression(traverse, &this->rhs_);
788
}
789
 
790
// Lower an assignment operation statement to a regular assignment
791
// statement.
792
 
793
Statement*
794
Assignment_operation_statement::do_lower(Gogo*, Named_object*,
795
                                         Block* enclosing, Statement_inserter*)
796
{
797
  Location loc = this->location();
798
 
799
  // We have to evaluate the left hand side expression only once.  We
800
  // do this by moving out any expression with side effects.
801
  Block* b = new Block(enclosing, loc);
802
  Move_ordered_evals moe(b);
803
  this->lhs_->traverse_subexpressions(&moe);
804
 
805
  Expression* lval = this->lhs_->copy();
806
 
807
  Operator op;
808
  switch (this->op_)
809
    {
810
    case OPERATOR_PLUSEQ:
811
      op = OPERATOR_PLUS;
812
      break;
813
    case OPERATOR_MINUSEQ:
814
      op = OPERATOR_MINUS;
815
      break;
816
    case OPERATOR_OREQ:
817
      op = OPERATOR_OR;
818
      break;
819
    case OPERATOR_XOREQ:
820
      op = OPERATOR_XOR;
821
      break;
822
    case OPERATOR_MULTEQ:
823
      op = OPERATOR_MULT;
824
      break;
825
    case OPERATOR_DIVEQ:
826
      op = OPERATOR_DIV;
827
      break;
828
    case OPERATOR_MODEQ:
829
      op = OPERATOR_MOD;
830
      break;
831
    case OPERATOR_LSHIFTEQ:
832
      op = OPERATOR_LSHIFT;
833
      break;
834
    case OPERATOR_RSHIFTEQ:
835
      op = OPERATOR_RSHIFT;
836
      break;
837
    case OPERATOR_ANDEQ:
838
      op = OPERATOR_AND;
839
      break;
840
    case OPERATOR_BITCLEAREQ:
841
      op = OPERATOR_BITCLEAR;
842
      break;
843
    default:
844
      go_unreachable();
845
    }
846
 
847
  Expression* binop = Expression::make_binary(op, lval, this->rhs_, loc);
848
  Statement* s = Statement::make_assignment(this->lhs_, binop, loc);
849
  if (b->statements()->empty())
850
    {
851
      delete b;
852
      return s;
853
    }
854
  else
855
    {
856
      b->add_statement(s);
857
      return Statement::make_block_statement(b, loc);
858
    }
859
}
860
 
861
// Dump the AST representation for an assignment operation statement
862
 
863
void
864
Assignment_operation_statement::do_dump_statement(
865
    Ast_dump_context* ast_dump_context) const
866
{
867
  ast_dump_context->print_indent();
868
  ast_dump_context->dump_expression(this->lhs_);
869
  ast_dump_context->dump_operator(this->op_);
870
  ast_dump_context->dump_expression(this->rhs_);
871
  ast_dump_context->ostream() << std::endl;
872
}
873
 
874
// Make an assignment operation statement.
875
 
876
Statement*
877
Statement::make_assignment_operation(Operator op, Expression* lhs,
878
                                     Expression* rhs, Location location)
879
{
880
  return new Assignment_operation_statement(op, lhs, rhs, location);
881
}
882
 
883
// A tuple assignment statement.  This differs from an assignment
884
// statement in that the right-hand-side expressions are evaluated in
885
// parallel.
886
 
887
class Tuple_assignment_statement : public Statement
888
{
889
 public:
890
  Tuple_assignment_statement(Expression_list* lhs, Expression_list* rhs,
891
                             Location location)
892
    : Statement(STATEMENT_TUPLE_ASSIGNMENT, location),
893
      lhs_(lhs), rhs_(rhs), are_hidden_fields_ok_(false)
894
  { }
895
 
896
  // Note that it is OK for this assignment statement to set hidden
897
  // fields.
898
  void
899
  set_hidden_fields_are_ok()
900
  { this->are_hidden_fields_ok_ = true; }
901
 
902
 protected:
903
  int
904
  do_traverse(Traverse* traverse);
905
 
906
  bool
907
  do_traverse_assignments(Traverse_assignments*)
908
  { go_unreachable(); }
909
 
910
  Statement*
911
  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
912
 
913
  Bstatement*
914
  do_get_backend(Translate_context*)
915
  { go_unreachable(); }
916
 
917
  void
918
  do_dump_statement(Ast_dump_context*) const;
919
 
920
 private:
921
  // Left hand side--a list of lvalues.
922
  Expression_list* lhs_;
923
  // Right hand side--a list of rvalues.
924
  Expression_list* rhs_;
925
  // True if this statement may set hidden fields in the assignment
926
  // statement.  This is used for generated method stubs.
927
  bool are_hidden_fields_ok_;
928
};
929
 
930
// Traversal.
931
 
932
int
933
Tuple_assignment_statement::do_traverse(Traverse* traverse)
934
{
935
  if (this->traverse_expression_list(traverse, this->lhs_) == TRAVERSE_EXIT)
936
    return TRAVERSE_EXIT;
937
  return this->traverse_expression_list(traverse, this->rhs_);
938
}
939
 
940
// Lower a tuple assignment.  We use temporary variables to split it
941
// up into a set of single assignments.
942
 
943
Statement*
944
Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
945
                                     Statement_inserter*)
946
{
947
  Location loc = this->location();
948
 
949
  Block* b = new Block(enclosing, loc);
950
 
951
  // First move out any subexpressions on the left hand side.  The
952
  // right hand side will be evaluated in the required order anyhow.
953
  Move_ordered_evals moe(b);
954
  for (Expression_list::iterator plhs = this->lhs_->begin();
955
       plhs != this->lhs_->end();
956
       ++plhs)
957
    Expression::traverse(&*plhs, &moe);
958
 
959
  std::vector<Temporary_statement*> temps;
960
  temps.reserve(this->lhs_->size());
961
 
962
  Expression_list::const_iterator prhs = this->rhs_->begin();
963
  for (Expression_list::const_iterator plhs = this->lhs_->begin();
964
       plhs != this->lhs_->end();
965
       ++plhs, ++prhs)
966
    {
967
      go_assert(prhs != this->rhs_->end());
968
 
969
      if ((*plhs)->is_error_expression()
970
          || (*plhs)->type()->is_error()
971
          || (*prhs)->is_error_expression()
972
          || (*prhs)->type()->is_error())
973
        continue;
974
 
975
      if ((*plhs)->is_sink_expression())
976
        {
977
          b->add_statement(Statement::make_statement(*prhs, true));
978
          continue;
979
        }
980
 
981
      Temporary_statement* temp = Statement::make_temporary((*plhs)->type(),
982
                                                            *prhs, loc);
983
      if (this->are_hidden_fields_ok_)
984
        temp->set_hidden_fields_are_ok();
985
      b->add_statement(temp);
986
      temps.push_back(temp);
987
 
988
    }
989
  go_assert(prhs == this->rhs_->end());
990
 
991
  prhs = this->rhs_->begin();
992
  std::vector<Temporary_statement*>::const_iterator ptemp = temps.begin();
993
  for (Expression_list::const_iterator plhs = this->lhs_->begin();
994
       plhs != this->lhs_->end();
995
       ++plhs, ++prhs)
996
    {
997
      if ((*plhs)->is_error_expression()
998
          || (*plhs)->type()->is_error()
999
          || (*prhs)->is_error_expression()
1000
          || (*prhs)->type()->is_error())
1001
        continue;
1002
 
1003
      if ((*plhs)->is_sink_expression())
1004
        continue;
1005
 
1006
      Expression* ref = Expression::make_temporary_reference(*ptemp, loc);
1007
      Statement* s = Statement::make_assignment(*plhs, ref, loc);
1008
      if (this->are_hidden_fields_ok_)
1009
        {
1010
          Assignment_statement* as = static_cast<Assignment_statement*>(s);
1011
          as->set_hidden_fields_are_ok();
1012
        }
1013
      b->add_statement(s);
1014
      ++ptemp;
1015
    }
1016
  go_assert(ptemp == temps.end());
1017
 
1018
  return Statement::make_block_statement(b, loc);
1019
}
1020
 
1021
// Dump the AST representation for a tuple assignment statement.
1022
 
1023
void
1024
Tuple_assignment_statement::do_dump_statement(
1025
    Ast_dump_context* ast_dump_context) const
1026
{
1027
  ast_dump_context->print_indent();
1028
  ast_dump_context->dump_expression_list(this->lhs_);
1029
  ast_dump_context->ostream() << " = ";
1030
  ast_dump_context->dump_expression_list(this->rhs_);
1031
  ast_dump_context->ostream()  << std::endl;
1032
}
1033
 
1034
// Make a tuple assignment statement.
1035
 
1036
Statement*
1037
Statement::make_tuple_assignment(Expression_list* lhs, Expression_list* rhs,
1038
                                 Location location)
1039
{
1040
  return new Tuple_assignment_statement(lhs, rhs, location);
1041
}
1042
 
1043
// A tuple assignment from a map index expression.
1044
//   v, ok = m[k]
1045
 
1046
class Tuple_map_assignment_statement : public Statement
1047
{
1048
public:
1049
  Tuple_map_assignment_statement(Expression* val, Expression* present,
1050
                                 Expression* map_index,
1051
                                 Location location)
1052
    : Statement(STATEMENT_TUPLE_MAP_ASSIGNMENT, location),
1053
      val_(val), present_(present), map_index_(map_index)
1054
  { }
1055
 
1056
 protected:
1057
  int
1058
  do_traverse(Traverse* traverse);
1059
 
1060
  bool
1061
  do_traverse_assignments(Traverse_assignments*)
1062
  { go_unreachable(); }
1063
 
1064
  Statement*
1065
  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1066
 
1067
  Bstatement*
1068
  do_get_backend(Translate_context*)
1069
  { go_unreachable(); }
1070
 
1071
  void
1072
  do_dump_statement(Ast_dump_context*) const;
1073
 
1074
 private:
1075
  // Lvalue which receives the value from the map.
1076
  Expression* val_;
1077
  // Lvalue which receives whether the key value was present.
1078
  Expression* present_;
1079
  // The map index expression.
1080
  Expression* map_index_;
1081
};
1082
 
1083
// Traversal.
1084
 
1085
int
1086
Tuple_map_assignment_statement::do_traverse(Traverse* traverse)
1087
{
1088
  if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
1089
      || this->traverse_expression(traverse, &this->present_) == TRAVERSE_EXIT)
1090
    return TRAVERSE_EXIT;
1091
  return this->traverse_expression(traverse, &this->map_index_);
1092
}
1093
 
1094
// Lower a tuple map assignment.
1095
 
1096
Statement*
1097
Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*,
1098
                                         Block* enclosing, Statement_inserter*)
1099
{
1100
  Location loc = this->location();
1101
 
1102
  Map_index_expression* map_index = this->map_index_->map_index_expression();
1103
  if (map_index == NULL)
1104
    {
1105
      this->report_error(_("expected map index on right hand side"));
1106
      return Statement::make_error_statement(loc);
1107
    }
1108
  Map_type* map_type = map_index->get_map_type();
1109
  if (map_type == NULL)
1110
    return Statement::make_error_statement(loc);
1111
 
1112
  Block* b = new Block(enclosing, loc);
1113
 
1114
  // Move out any subexpressions to make sure that functions are
1115
  // called in the required order.
1116
  Move_ordered_evals moe(b);
1117
  this->val_->traverse_subexpressions(&moe);
1118
  this->present_->traverse_subexpressions(&moe);
1119
 
1120
  // Copy the key value into a temporary so that we can take its
1121
  // address without pushing the value onto the heap.
1122
 
1123
  // var key_temp KEY_TYPE = MAP_INDEX
1124
  Temporary_statement* key_temp =
1125
    Statement::make_temporary(map_type->key_type(), map_index->index(), loc);
1126
  b->add_statement(key_temp);
1127
 
1128
  // var val_temp VAL_TYPE
1129
  Temporary_statement* val_temp =
1130
    Statement::make_temporary(map_type->val_type(), NULL, loc);
1131
  b->add_statement(val_temp);
1132
 
1133
  // var present_temp bool
1134
  Temporary_statement* present_temp =
1135
    Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
1136
  b->add_statement(present_temp);
1137
 
1138
  // present_temp = mapaccess2(DESCRIPTOR, MAP, &key_temp, &val_temp)
1139
  Expression* a1 = Expression::make_type_descriptor(map_type, loc);
1140
  Expression* a2 = map_index->map();
1141
  Temporary_reference_expression* ref =
1142
    Expression::make_temporary_reference(key_temp, loc);
1143
  Expression* a3 = Expression::make_unary(OPERATOR_AND, ref, loc);
1144
  ref = Expression::make_temporary_reference(val_temp, loc);
1145
  Expression* a4 = Expression::make_unary(OPERATOR_AND, ref, loc);
1146
  Expression* call = Runtime::make_call(Runtime::MAPACCESS2, loc, 4,
1147
                                        a1, a2, a3, a4);
1148
 
1149
  ref = Expression::make_temporary_reference(present_temp, loc);
1150
  ref->set_is_lvalue();
1151
  Statement* s = Statement::make_assignment(ref, call, loc);
1152
  b->add_statement(s);
1153
 
1154
  // val = val_temp
1155
  ref = Expression::make_temporary_reference(val_temp, loc);
1156
  s = Statement::make_assignment(this->val_, ref, loc);
1157
  b->add_statement(s);
1158
 
1159
  // present = present_temp
1160
  ref = Expression::make_temporary_reference(present_temp, loc);
1161
  s = Statement::make_assignment(this->present_, ref, loc);
1162
  b->add_statement(s);
1163
 
1164
  return Statement::make_block_statement(b, loc);
1165
}
1166
 
1167
// Dump the AST representation for a tuple map assignment statement.
1168
 
1169
void
1170
Tuple_map_assignment_statement::do_dump_statement(
1171
    Ast_dump_context* ast_dump_context) const
1172
{
1173
  ast_dump_context->print_indent();
1174
  ast_dump_context->dump_expression(this->val_);
1175
  ast_dump_context->ostream() << ", ";
1176
  ast_dump_context->dump_expression(this->present_);
1177
  ast_dump_context->ostream() << " = ";
1178
  ast_dump_context->dump_expression(this->map_index_);
1179
  ast_dump_context->ostream() << std::endl;
1180
}
1181
 
1182
// Make a map assignment statement which returns a pair of values.
1183
 
1184
Statement*
1185
Statement::make_tuple_map_assignment(Expression* val, Expression* present,
1186
                                     Expression* map_index,
1187
                                     Location location)
1188
{
1189
  return new Tuple_map_assignment_statement(val, present, map_index, location);
1190
}
1191
 
1192
// Assign a pair of entries to a map.
1193
//   m[k] = v, p
1194
 
1195
class Map_assignment_statement : public Statement
1196
{
1197
 public:
1198
  Map_assignment_statement(Expression* map_index,
1199
                           Expression* val, Expression* should_set,
1200
                           Location location)
1201
    : Statement(STATEMENT_MAP_ASSIGNMENT, location),
1202
      map_index_(map_index), val_(val), should_set_(should_set)
1203
  { }
1204
 
1205
 protected:
1206
  int
1207
  do_traverse(Traverse* traverse);
1208
 
1209
  bool
1210
  do_traverse_assignments(Traverse_assignments*)
1211
  { go_unreachable(); }
1212
 
1213
  Statement*
1214
  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1215
 
1216
  Bstatement*
1217
  do_get_backend(Translate_context*)
1218
  { go_unreachable(); }
1219
 
1220
  void
1221
  do_dump_statement(Ast_dump_context*) const;
1222
 
1223
 private:
1224
  // A reference to the map index which should be set or deleted.
1225
  Expression* map_index_;
1226
  // The value to add to the map.
1227
  Expression* val_;
1228
  // Whether or not to add the value.
1229
  Expression* should_set_;
1230
};
1231
 
1232
// Traverse a map assignment.
1233
 
1234
int
1235
Map_assignment_statement::do_traverse(Traverse* traverse)
1236
{
1237
  if (this->traverse_expression(traverse, &this->map_index_) == TRAVERSE_EXIT
1238
      || this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
1239
    return TRAVERSE_EXIT;
1240
  return this->traverse_expression(traverse, &this->should_set_);
1241
}
1242
 
1243
// Lower a map assignment to a function call.
1244
 
1245
Statement*
1246
Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
1247
                                   Statement_inserter*)
1248
{
1249
  Location loc = this->location();
1250
 
1251
  Map_index_expression* map_index = this->map_index_->map_index_expression();
1252
  if (map_index == NULL)
1253
    {
1254
      this->report_error(_("expected map index on left hand side"));
1255
      return Statement::make_error_statement(loc);
1256
    }
1257
  Map_type* map_type = map_index->get_map_type();
1258
  if (map_type == NULL)
1259
    return Statement::make_error_statement(loc);
1260
 
1261
  Block* b = new Block(enclosing, loc);
1262
 
1263
  // Evaluate the map first to get order of evaluation right.
1264
  // map_temp := m // we are evaluating m[k] = v, p
1265
  Temporary_statement* map_temp = Statement::make_temporary(map_type,
1266
                                                            map_index->map(),
1267
                                                            loc);
1268
  b->add_statement(map_temp);
1269
 
1270
  // var key_temp MAP_KEY_TYPE = k
1271
  Temporary_statement* key_temp =
1272
    Statement::make_temporary(map_type->key_type(), map_index->index(), loc);
1273
  b->add_statement(key_temp);
1274
 
1275
  // var val_temp MAP_VAL_TYPE = v
1276
  Temporary_statement* val_temp =
1277
    Statement::make_temporary(map_type->val_type(), this->val_, loc);
1278
  b->add_statement(val_temp);
1279
 
1280
  // var insert_temp bool = p
1281
  Temporary_statement* insert_temp =
1282
    Statement::make_temporary(Type::lookup_bool_type(), this->should_set_,
1283
                              loc);
1284
  b->add_statement(insert_temp);
1285
 
1286
  // mapassign2(map_temp, &key_temp, &val_temp, p)
1287
  Expression* p1 = Expression::make_temporary_reference(map_temp, loc);
1288
  Expression* ref = Expression::make_temporary_reference(key_temp, loc);
1289
  Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
1290
  ref = Expression::make_temporary_reference(val_temp, loc);
1291
  Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
1292
  Expression* p4 = Expression::make_temporary_reference(insert_temp, loc);
1293
  Expression* call = Runtime::make_call(Runtime::MAPASSIGN2, loc, 4,
1294
                                        p1, p2, p3, p4);
1295
  Statement* s = Statement::make_statement(call, true);
1296
  b->add_statement(s);
1297
 
1298
  return Statement::make_block_statement(b, loc);
1299
}
1300
 
1301
// Dump the AST representation for a map assignment statement.
1302
 
1303
void
1304
Map_assignment_statement::do_dump_statement(
1305
    Ast_dump_context* ast_dump_context) const
1306
{
1307
  ast_dump_context->print_indent();
1308
  ast_dump_context->dump_expression(this->map_index_);
1309
  ast_dump_context->ostream() << " = ";
1310
  ast_dump_context->dump_expression(this->val_);
1311
  ast_dump_context->ostream() << ", ";
1312
  ast_dump_context->dump_expression(this->should_set_);
1313
  ast_dump_context->ostream() << std::endl;
1314
}
1315
 
1316
// Make a statement which assigns a pair of entries to a map.
1317
 
1318
Statement*
1319
Statement::make_map_assignment(Expression* map_index,
1320
                               Expression* val, Expression* should_set,
1321
                               Location location)
1322
{
1323
  return new Map_assignment_statement(map_index, val, should_set, location);
1324
}
1325
 
1326
// A tuple assignment from a receive statement.
1327
 
1328
class Tuple_receive_assignment_statement : public Statement
1329
{
1330
 public:
1331
  Tuple_receive_assignment_statement(Expression* val, Expression* closed,
1332
                                     Expression* channel, Location location)
1333
    : Statement(STATEMENT_TUPLE_RECEIVE_ASSIGNMENT, location),
1334
      val_(val), closed_(closed), channel_(channel)
1335
  { }
1336
 
1337
 protected:
1338
  int
1339
  do_traverse(Traverse* traverse);
1340
 
1341
  bool
1342
  do_traverse_assignments(Traverse_assignments*)
1343
  { go_unreachable(); }
1344
 
1345
  Statement*
1346
  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1347
 
1348
  Bstatement*
1349
  do_get_backend(Translate_context*)
1350
  { go_unreachable(); }
1351
 
1352
  void
1353
  do_dump_statement(Ast_dump_context*) const;
1354
 
1355
 private:
1356
  // Lvalue which receives the value from the channel.
1357
  Expression* val_;
1358
  // Lvalue which receives whether the channel is closed.
1359
  Expression* closed_;
1360
  // The channel on which we receive the value.
1361
  Expression* channel_;
1362
};
1363
 
1364
// Traversal.
1365
 
1366
int
1367
Tuple_receive_assignment_statement::do_traverse(Traverse* traverse)
1368
{
1369
  if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
1370
      || this->traverse_expression(traverse, &this->closed_) == TRAVERSE_EXIT)
1371
    return TRAVERSE_EXIT;
1372
  return this->traverse_expression(traverse, &this->channel_);
1373
}
1374
 
1375
// Lower to a function call.
1376
 
1377
Statement*
1378
Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
1379
                                             Block* enclosing,
1380
                                             Statement_inserter*)
1381
{
1382
  Location loc = this->location();
1383
 
1384
  Channel_type* channel_type = this->channel_->type()->channel_type();
1385
  if (channel_type == NULL)
1386
    {
1387
      this->report_error(_("expected channel"));
1388
      return Statement::make_error_statement(loc);
1389
    }
1390
  if (!channel_type->may_receive())
1391
    {
1392
      this->report_error(_("invalid receive on send-only channel"));
1393
      return Statement::make_error_statement(loc);
1394
    }
1395
 
1396
  Block* b = new Block(enclosing, loc);
1397
 
1398
  // Make sure that any subexpressions on the left hand side are
1399
  // evaluated in the right order.
1400
  Move_ordered_evals moe(b);
1401
  this->val_->traverse_subexpressions(&moe);
1402
  this->closed_->traverse_subexpressions(&moe);
1403
 
1404
  // var val_temp ELEMENT_TYPE
1405
  Temporary_statement* val_temp =
1406
    Statement::make_temporary(channel_type->element_type(), NULL, loc);
1407
  b->add_statement(val_temp);
1408
 
1409
  // var closed_temp bool
1410
  Temporary_statement* closed_temp =
1411
    Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
1412
  b->add_statement(closed_temp);
1413
 
1414
  // closed_temp = chanrecv2(type, channel, &val_temp)
1415
  Expression* td = Expression::make_type_descriptor(this->channel_->type(),
1416
                                                    loc);
1417
  Temporary_reference_expression* ref =
1418
    Expression::make_temporary_reference(val_temp, loc);
1419
  Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
1420
  Expression* call = Runtime::make_call(Runtime::CHANRECV2,
1421
                                        loc, 3, td, this->channel_, p2);
1422
  ref = Expression::make_temporary_reference(closed_temp, loc);
1423
  ref->set_is_lvalue();
1424
  Statement* s = Statement::make_assignment(ref, call, loc);
1425
  b->add_statement(s);
1426
 
1427
  // val = val_temp
1428
  ref = Expression::make_temporary_reference(val_temp, loc);
1429
  s = Statement::make_assignment(this->val_, ref, loc);
1430
  b->add_statement(s);
1431
 
1432
  // closed = closed_temp
1433
  ref = Expression::make_temporary_reference(closed_temp, loc);
1434
  s = Statement::make_assignment(this->closed_, ref, loc);
1435
  b->add_statement(s);
1436
 
1437
  return Statement::make_block_statement(b, loc);
1438
}
1439
 
1440
// Dump the AST representation for a tuple receive statement.
1441
 
1442
void
1443
Tuple_receive_assignment_statement::do_dump_statement(
1444
    Ast_dump_context* ast_dump_context) const
1445
{
1446
  ast_dump_context->print_indent();
1447
  ast_dump_context->dump_expression(this->val_);
1448
  ast_dump_context->ostream() << ", ";
1449
  ast_dump_context->dump_expression(this->closed_);
1450
  ast_dump_context->ostream() << " <- ";
1451
  ast_dump_context->dump_expression(this->channel_);
1452
  ast_dump_context->ostream() << std::endl;
1453
}
1454
 
1455
// Make a nonblocking receive statement.
1456
 
1457
Statement*
1458
Statement::make_tuple_receive_assignment(Expression* val, Expression* closed,
1459
                                         Expression* channel,
1460
                                         Location location)
1461
{
1462
  return new Tuple_receive_assignment_statement(val, closed, channel,
1463
                                                location);
1464
}
1465
 
1466
// An assignment to a pair of values from a type guard.  This is a
1467
// conditional type guard.  v, ok = i.(type).
1468
 
1469
class Tuple_type_guard_assignment_statement : public Statement
1470
{
1471
 public:
1472
  Tuple_type_guard_assignment_statement(Expression* val, Expression* ok,
1473
                                        Expression* expr, Type* type,
1474
                                        Location location)
1475
    : Statement(STATEMENT_TUPLE_TYPE_GUARD_ASSIGNMENT, location),
1476
      val_(val), ok_(ok), expr_(expr), type_(type)
1477
  { }
1478
 
1479
 protected:
1480
  int
1481
  do_traverse(Traverse*);
1482
 
1483
  bool
1484
  do_traverse_assignments(Traverse_assignments*)
1485
  { go_unreachable(); }
1486
 
1487
  Statement*
1488
  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1489
 
1490
  Bstatement*
1491
  do_get_backend(Translate_context*)
1492
  { go_unreachable(); }
1493
 
1494
  void
1495
  do_dump_statement(Ast_dump_context*) const;
1496
 
1497
 private:
1498
  Call_expression*
1499
  lower_to_type(Runtime::Function);
1500
 
1501
  void
1502
  lower_to_object_type(Block*, Runtime::Function);
1503
 
1504
  // The variable which recieves the converted value.
1505
  Expression* val_;
1506
  // The variable which receives the indication of success.
1507
  Expression* ok_;
1508
  // The expression being converted.
1509
  Expression* expr_;
1510
  // The type to which the expression is being converted.
1511
  Type* type_;
1512
};
1513
 
1514
// Traverse a type guard tuple assignment.
1515
 
1516
int
1517
Tuple_type_guard_assignment_statement::do_traverse(Traverse* traverse)
1518
{
1519
  if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
1520
      || this->traverse_expression(traverse, &this->ok_) == TRAVERSE_EXIT
1521
      || this->traverse_type(traverse, this->type_) == TRAVERSE_EXIT)
1522
    return TRAVERSE_EXIT;
1523
  return this->traverse_expression(traverse, &this->expr_);
1524
}
1525
 
1526
// Lower to a function call.
1527
 
1528
Statement*
1529
Tuple_type_guard_assignment_statement::do_lower(Gogo*, Named_object*,
1530
                                                Block* enclosing,
1531
                                                Statement_inserter*)
1532
{
1533
  Location loc = this->location();
1534
 
1535
  Type* expr_type = this->expr_->type();
1536
  if (expr_type->interface_type() == NULL)
1537
    {
1538
      if (!expr_type->is_error() && !this->type_->is_error())
1539
        this->report_error(_("type assertion only valid for interface types"));
1540
      return Statement::make_error_statement(loc);
1541
    }
1542
 
1543
  Block* b = new Block(enclosing, loc);
1544
 
1545
  // Make sure that any subexpressions on the left hand side are
1546
  // evaluated in the right order.
1547
  Move_ordered_evals moe(b);
1548
  this->val_->traverse_subexpressions(&moe);
1549
  this->ok_->traverse_subexpressions(&moe);
1550
 
1551
  bool expr_is_empty = expr_type->interface_type()->is_empty();
1552
  Call_expression* call;
1553
  if (this->type_->interface_type() != NULL)
1554
    {
1555
      if (this->type_->interface_type()->is_empty())
1556
        call = Runtime::make_call((expr_is_empty
1557
                                   ? Runtime::IFACEE2E2
1558
                                   : Runtime::IFACEI2E2),
1559
                                  loc, 1, this->expr_);
1560
      else
1561
        call = this->lower_to_type(expr_is_empty
1562
                                   ? Runtime::IFACEE2I2
1563
                                   : Runtime::IFACEI2I2);
1564
    }
1565
  else if (this->type_->points_to() != NULL)
1566
    call = this->lower_to_type(expr_is_empty
1567
                               ? Runtime::IFACEE2T2P
1568
                               : Runtime::IFACEI2T2P);
1569
  else
1570
    {
1571
      this->lower_to_object_type(b,
1572
                                 (expr_is_empty
1573
                                  ? Runtime::IFACEE2T2
1574
                                  : Runtime::IFACEI2T2));
1575
      call = NULL;
1576
    }
1577
 
1578
  if (call != NULL)
1579
    {
1580
      Expression* res = Expression::make_call_result(call, 0);
1581
      res = Expression::make_unsafe_cast(this->type_, res, loc);
1582
      Statement* s = Statement::make_assignment(this->val_, res, loc);
1583
      b->add_statement(s);
1584
 
1585
      res = Expression::make_call_result(call, 1);
1586
      s = Statement::make_assignment(this->ok_, res, loc);
1587
      b->add_statement(s);
1588
    }
1589
 
1590
  return Statement::make_block_statement(b, loc);
1591
}
1592
 
1593
// Lower a conversion to a non-empty interface type or a pointer type.
1594
 
1595
Call_expression*
1596
Tuple_type_guard_assignment_statement::lower_to_type(Runtime::Function code)
1597
{
1598
  Location loc = this->location();
1599
  return Runtime::make_call(code, loc, 2,
1600
                            Expression::make_type_descriptor(this->type_, loc),
1601
                            this->expr_);
1602
}
1603
 
1604
// Lower a conversion to a non-interface non-pointer type.
1605
 
1606
void
1607
Tuple_type_guard_assignment_statement::lower_to_object_type(
1608
    Block* b,
1609
    Runtime::Function code)
1610
{
1611
  Location loc = this->location();
1612
 
1613
  // var val_temp TYPE
1614
  Temporary_statement* val_temp = Statement::make_temporary(this->type_,
1615
                                                            NULL, loc);
1616
  b->add_statement(val_temp);
1617
 
1618
  // ok = CODE(type_descriptor, expr, &val_temp)
1619
  Expression* p1 = Expression::make_type_descriptor(this->type_, loc);
1620
  Expression* ref = Expression::make_temporary_reference(val_temp, loc);
1621
  Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
1622
  Expression* call = Runtime::make_call(code, loc, 3, p1, this->expr_, p3);
1623
  Statement* s = Statement::make_assignment(this->ok_, call, loc);
1624
  b->add_statement(s);
1625
 
1626
  // val = val_temp
1627
  ref = Expression::make_temporary_reference(val_temp, loc);
1628
  s = Statement::make_assignment(this->val_, ref, loc);
1629
  b->add_statement(s);
1630
}
1631
 
1632
// Dump the AST representation for a tuple type guard statement.
1633
 
1634
void
1635
Tuple_type_guard_assignment_statement::do_dump_statement(
1636
    Ast_dump_context* ast_dump_context) const
1637
{
1638
  ast_dump_context->print_indent();
1639
  ast_dump_context->dump_expression(this->val_);
1640
  ast_dump_context->ostream() << ", ";
1641
  ast_dump_context->dump_expression(this->ok_);
1642
  ast_dump_context->ostream() << " = ";
1643
  ast_dump_context->dump_expression(this->expr_);
1644
  ast_dump_context->ostream() << " . ";
1645
  ast_dump_context->dump_type(this->type_);
1646
  ast_dump_context->ostream()  << std::endl;
1647
}
1648
 
1649
// Make an assignment from a type guard to a pair of variables.
1650
 
1651
Statement*
1652
Statement::make_tuple_type_guard_assignment(Expression* val, Expression* ok,
1653
                                            Expression* expr, Type* type,
1654
                                            Location location)
1655
{
1656
  return new Tuple_type_guard_assignment_statement(val, ok, expr, type,
1657
                                                   location);
1658
}
1659
 
1660
// An expression statement.
1661
 
1662
class Expression_statement : public Statement
1663
{
1664
 public:
1665
  Expression_statement(Expression* expr, bool is_ignored)
1666
    : Statement(STATEMENT_EXPRESSION, expr->location()),
1667
      expr_(expr), is_ignored_(is_ignored)
1668
  { }
1669
 
1670
  Expression*
1671
  expr()
1672
  { return this->expr_; }
1673
 
1674
 protected:
1675
  int
1676
  do_traverse(Traverse* traverse)
1677
  { return this->traverse_expression(traverse, &this->expr_); }
1678
 
1679
  void
1680
  do_determine_types()
1681
  { this->expr_->determine_type_no_context(); }
1682
 
1683
  void
1684
  do_check_types(Gogo*);
1685
 
1686
  bool
1687
  do_may_fall_through() const;
1688
 
1689
  Bstatement*
1690
  do_get_backend(Translate_context* context);
1691
 
1692
  void
1693
  do_dump_statement(Ast_dump_context*) const;
1694
 
1695
 private:
1696
  Expression* expr_;
1697
  // Whether the value of this expression is being explicitly ignored.
1698
  bool is_ignored_;
1699
};
1700
 
1701
// Check the types of an expression statement.  The only check we do
1702
// is to possibly give an error about discarding the value of the
1703
// expression.
1704
 
1705
void
1706
Expression_statement::do_check_types(Gogo*)
1707
{
1708
  if (!this->is_ignored_)
1709
    this->expr_->discarding_value();
1710
}
1711
 
1712
// An expression statement may fall through unless it is a call to a
1713
// function which does not return.
1714
 
1715
bool
1716
Expression_statement::do_may_fall_through() const
1717
{
1718
  const Call_expression* call = this->expr_->call_expression();
1719
  if (call != NULL)
1720
    {
1721
      const Expression* fn = call->fn();
1722
      const Func_expression* fe = fn->func_expression();
1723
      if (fe != NULL)
1724
        {
1725
          const Named_object* no = fe->named_object();
1726
 
1727
          Function_type* fntype;
1728
          if (no->is_function())
1729
            fntype = no->func_value()->type();
1730
          else if (no->is_function_declaration())
1731
            fntype = no->func_declaration_value()->type();
1732
          else
1733
            fntype = NULL;
1734
 
1735
          // The builtin function panic does not return.
1736
          if (fntype != NULL && fntype->is_builtin() && no->name() == "panic")
1737
            return false;
1738
        }
1739
    }
1740
  return true;
1741
}
1742
 
1743
// Convert to backend representation.
1744
 
1745
Bstatement*
1746
Expression_statement::do_get_backend(Translate_context* context)
1747
{
1748
  tree expr_tree = this->expr_->get_tree(context);
1749
  return context->backend()->expression_statement(tree_to_expr(expr_tree));
1750
}
1751
 
1752
// Dump the AST representation for an expression statement
1753
 
1754
void
1755
Expression_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
1756
    const
1757
{
1758
  ast_dump_context->print_indent();
1759
  ast_dump_context->dump_expression(expr_);
1760
  ast_dump_context->ostream() << std::endl;
1761
}
1762
 
1763
// Make an expression statement from an Expression.
1764
 
1765
Statement*
1766
Statement::make_statement(Expression* expr, bool is_ignored)
1767
{
1768
  return new Expression_statement(expr, is_ignored);
1769
}
1770
 
1771
// A block statement--a list of statements which may include variable
1772
// definitions.
1773
 
1774
class Block_statement : public Statement
1775
{
1776
 public:
1777
  Block_statement(Block* block, Location location)
1778
    : Statement(STATEMENT_BLOCK, location),
1779
      block_(block)
1780
  { }
1781
 
1782
 protected:
1783
  int
1784
  do_traverse(Traverse* traverse)
1785
  { return this->block_->traverse(traverse); }
1786
 
1787
  void
1788
  do_determine_types()
1789
  { this->block_->determine_types(); }
1790
 
1791
  bool
1792
  do_may_fall_through() const
1793
  { return this->block_->may_fall_through(); }
1794
 
1795
  Bstatement*
1796
  do_get_backend(Translate_context* context);
1797
 
1798
  void
1799
  do_dump_statement(Ast_dump_context*) const;
1800
 
1801
 private:
1802
  Block* block_;
1803
};
1804
 
1805
// Convert a block to the backend representation of a statement.
1806
 
1807
Bstatement*
1808
Block_statement::do_get_backend(Translate_context* context)
1809
{
1810
  Bblock* bblock = this->block_->get_backend(context);
1811
  return context->backend()->block_statement(bblock);
1812
}
1813
 
1814
// Dump the AST for a block statement
1815
 
1816
void
1817
Block_statement::do_dump_statement(Ast_dump_context*) const
1818
{
1819
  // block statement braces are dumped when traversing.
1820
}
1821
 
1822
// Make a block statement.
1823
 
1824
Statement*
1825
Statement::make_block_statement(Block* block, Location location)
1826
{
1827
  return new Block_statement(block, location);
1828
}
1829
 
1830
// An increment or decrement statement.
1831
 
1832
class Inc_dec_statement : public Statement
1833
{
1834
 public:
1835
  Inc_dec_statement(bool is_inc, Expression* expr)
1836
    : Statement(STATEMENT_INCDEC, expr->location()),
1837
      expr_(expr), is_inc_(is_inc)
1838
  { }
1839
 
1840
 protected:
1841
  int
1842
  do_traverse(Traverse* traverse)
1843
  { return this->traverse_expression(traverse, &this->expr_); }
1844
 
1845
  bool
1846
  do_traverse_assignments(Traverse_assignments*)
1847
  { go_unreachable(); }
1848
 
1849
  Statement*
1850
  do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
1851
 
1852
  Bstatement*
1853
  do_get_backend(Translate_context*)
1854
  { go_unreachable(); }
1855
 
1856
  void
1857
  do_dump_statement(Ast_dump_context*) const;
1858
 
1859
 private:
1860
  // The l-value to increment or decrement.
1861
  Expression* expr_;
1862
  // Whether to increment or decrement.
1863
  bool is_inc_;
1864
};
1865
 
1866
// Lower to += or -=.
1867
 
1868
Statement*
1869
Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*, Statement_inserter*)
1870
{
1871
  Location loc = this->location();
1872
 
1873
  mpz_t oval;
1874
  mpz_init_set_ui(oval, 1UL);
1875
  Expression* oexpr = Expression::make_integer(&oval, NULL, loc);
1876
  mpz_clear(oval);
1877
 
1878
  Operator op = this->is_inc_ ? OPERATOR_PLUSEQ : OPERATOR_MINUSEQ;
1879
  return Statement::make_assignment_operation(op, this->expr_, oexpr, loc);
1880
}
1881
 
1882
// Dump the AST representation for a inc/dec statement.
1883
 
1884
void
1885
Inc_dec_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
1886
{
1887
  ast_dump_context->print_indent();
1888
  ast_dump_context->dump_expression(expr_);
1889
  ast_dump_context->ostream() << (is_inc_? "++": "--") << std::endl;
1890
}
1891
 
1892
// Make an increment statement.
1893
 
1894
Statement*
1895
Statement::make_inc_statement(Expression* expr)
1896
{
1897
  return new Inc_dec_statement(true, expr);
1898
}
1899
 
1900
// Make a decrement statement.
1901
 
1902
Statement*
1903
Statement::make_dec_statement(Expression* expr)
1904
{
1905
  return new Inc_dec_statement(false, expr);
1906
}
1907
 
1908
// Class Thunk_statement.  This is the base class for go and defer
1909
// statements.
1910
 
1911
// Constructor.
1912
 
1913
Thunk_statement::Thunk_statement(Statement_classification classification,
1914
                                 Call_expression* call,
1915
                                 Location location)
1916
    : Statement(classification, location),
1917
      call_(call), struct_type_(NULL)
1918
{
1919
}
1920
 
1921
// Return whether this is a simple statement which does not require a
1922
// thunk.
1923
 
1924
bool
1925
Thunk_statement::is_simple(Function_type* fntype) const
1926
{
1927
  // We need a thunk to call a method, or to pass a variable number of
1928
  // arguments.
1929
  if (fntype->is_method() || fntype->is_varargs())
1930
    return false;
1931
 
1932
  // A defer statement requires a thunk to set up for whether the
1933
  // function can call recover.
1934
  if (this->classification() == STATEMENT_DEFER)
1935
    return false;
1936
 
1937
  // We can only permit a single parameter of pointer type.
1938
  const Typed_identifier_list* parameters = fntype->parameters();
1939
  if (parameters != NULL
1940
      && (parameters->size() > 1
1941
          || (parameters->size() == 1
1942
              && parameters->begin()->type()->points_to() == NULL)))
1943
    return false;
1944
 
1945
  // If the function returns multiple values, or returns a type other
1946
  // than integer, floating point, or pointer, then it may get a
1947
  // hidden first parameter, in which case we need the more
1948
  // complicated approach.  This is true even though we are going to
1949
  // ignore the return value.
1950
  const Typed_identifier_list* results = fntype->results();
1951
  if (results != NULL
1952
      && (results->size() > 1
1953
          || (results->size() == 1
1954
              && !results->begin()->type()->is_basic_type()
1955
              && results->begin()->type()->points_to() == NULL)))
1956
    return false;
1957
 
1958
  // If this calls something which is not a simple function, then we
1959
  // need a thunk.
1960
  Expression* fn = this->call_->call_expression()->fn();
1961
  if (fn->interface_field_reference_expression() != NULL)
1962
    return false;
1963
 
1964
  return true;
1965
}
1966
 
1967
// Traverse a thunk statement.
1968
 
1969
int
1970
Thunk_statement::do_traverse(Traverse* traverse)
1971
{
1972
  return this->traverse_expression(traverse, &this->call_);
1973
}
1974
 
1975
// We implement traverse_assignment for a thunk statement because it
1976
// effectively copies the function call.
1977
 
1978
bool
1979
Thunk_statement::do_traverse_assignments(Traverse_assignments* tassign)
1980
{
1981
  Expression* fn = this->call_->call_expression()->fn();
1982
  Expression* fn2 = fn;
1983
  tassign->value(&fn2, true, false);
1984
  return true;
1985
}
1986
 
1987
// Determine types in a thunk statement.
1988
 
1989
void
1990
Thunk_statement::do_determine_types()
1991
{
1992
  this->call_->determine_type_no_context();
1993
 
1994
  // Now that we know the types of the call, build the struct used to
1995
  // pass parameters.
1996
  Call_expression* ce = this->call_->call_expression();
1997
  if (ce == NULL)
1998
    return;
1999
  Function_type* fntype = ce->get_function_type();
2000
  if (fntype != NULL && !this->is_simple(fntype))
2001
    this->struct_type_ = this->build_struct(fntype);
2002
}
2003
 
2004
// Check types in a thunk statement.
2005
 
2006
void
2007
Thunk_statement::do_check_types(Gogo*)
2008
{
2009
  Call_expression* ce = this->call_->call_expression();
2010
  if (ce == NULL)
2011
    {
2012
      if (!this->call_->is_error_expression())
2013
        this->report_error("expected call expression");
2014
      return;
2015
    }
2016
}
2017
 
2018
// The Traverse class used to find and simplify thunk statements.
2019
 
2020
class Simplify_thunk_traverse : public Traverse
2021
{
2022
 public:
2023
  Simplify_thunk_traverse(Gogo* gogo)
2024
    : Traverse(traverse_functions | traverse_blocks),
2025
      gogo_(gogo), function_(NULL)
2026
  { }
2027
 
2028
  int
2029
  function(Named_object*);
2030
 
2031
  int
2032
  block(Block*);
2033
 
2034
 private:
2035
  // General IR.
2036
  Gogo* gogo_;
2037
  // The function we are traversing.
2038
  Named_object* function_;
2039
};
2040
 
2041
// Keep track of the current function while looking for thunks.
2042
 
2043
int
2044
Simplify_thunk_traverse::function(Named_object* no)
2045
{
2046
  go_assert(this->function_ == NULL);
2047
  this->function_ = no;
2048
  int t = no->func_value()->traverse(this);
2049
  this->function_ = NULL;
2050
  if (t == TRAVERSE_EXIT)
2051
    return t;
2052
  return TRAVERSE_SKIP_COMPONENTS;
2053
}
2054
 
2055
// Look for thunks in a block.
2056
 
2057
int
2058
Simplify_thunk_traverse::block(Block* b)
2059
{
2060
  // The parser ensures that thunk statements always appear at the end
2061
  // of a block.
2062
  if (b->statements()->size() < 1)
2063
    return TRAVERSE_CONTINUE;
2064
  Thunk_statement* stat = b->statements()->back()->thunk_statement();
2065
  if (stat == NULL)
2066
    return TRAVERSE_CONTINUE;
2067
  if (stat->simplify_statement(this->gogo_, this->function_, b))
2068
    return TRAVERSE_SKIP_COMPONENTS;
2069
  return TRAVERSE_CONTINUE;
2070
}
2071
 
2072
// Simplify all thunk statements.
2073
 
2074
void
2075
Gogo::simplify_thunk_statements()
2076
{
2077
  Simplify_thunk_traverse thunk_traverse(this);
2078
  this->traverse(&thunk_traverse);
2079
}
2080
 
2081
// Return true if the thunk function is a constant, which means that
2082
// it does not need to be passed to the thunk routine.
2083
 
2084
bool
2085
Thunk_statement::is_constant_function() const
2086
{
2087
  Call_expression* ce = this->call_->call_expression();
2088
  Function_type* fntype = ce->get_function_type();
2089
  if (fntype == NULL)
2090
    {
2091
      go_assert(saw_errors());
2092
      return false;
2093
    }
2094
  if (fntype->is_builtin())
2095
    return true;
2096
  Expression* fn = ce->fn();
2097
  if (fn->func_expression() != NULL)
2098
    return fn->func_expression()->closure() == NULL;
2099
  if (fn->interface_field_reference_expression() != NULL)
2100
    return true;
2101
  return false;
2102
}
2103
 
2104
// Simplify complex thunk statements into simple ones.  A complicated
2105
// thunk statement is one which takes anything other than zero
2106
// parameters or a single pointer parameter.  We rewrite it into code
2107
// which allocates a struct, stores the parameter values into the
2108
// struct, and does a simple go or defer statement which passes the
2109
// struct to a thunk.  The thunk does the real call.
2110
 
2111
bool
2112
Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
2113
                                    Block* block)
2114
{
2115
  if (this->classification() == STATEMENT_ERROR)
2116
    return false;
2117
  if (this->call_->is_error_expression())
2118
    return false;
2119
 
2120
  if (this->classification() == STATEMENT_DEFER)
2121
    {
2122
      // Make sure that the defer stack exists for the function.  We
2123
      // will use when converting this statement to the backend
2124
      // representation, but we want it to exist when we start
2125
      // converting the function.
2126
      function->func_value()->defer_stack(this->location());
2127
    }
2128
 
2129
  Call_expression* ce = this->call_->call_expression();
2130
  Function_type* fntype = ce->get_function_type();
2131
  if (fntype == NULL)
2132
    {
2133
      go_assert(saw_errors());
2134
      this->set_is_error();
2135
      return false;
2136
    }
2137
  if (this->is_simple(fntype))
2138
    return false;
2139
 
2140
  Expression* fn = ce->fn();
2141
  Interface_field_reference_expression* interface_method =
2142
    fn->interface_field_reference_expression();
2143
 
2144
  Location location = this->location();
2145
 
2146
  std::string thunk_name = Gogo::thunk_name();
2147
 
2148
  // Build the thunk.
2149
  this->build_thunk(gogo, thunk_name);
2150
 
2151
  // Generate code to call the thunk.
2152
 
2153
  // Get the values to store into the struct which is the single
2154
  // argument to the thunk.
2155
 
2156
  Expression_list* vals = new Expression_list();
2157
  if (!this->is_constant_function())
2158
    vals->push_back(fn);
2159
 
2160
  if (interface_method != NULL)
2161
    vals->push_back(interface_method->expr());
2162
 
2163
  if (ce->args() != NULL)
2164
    {
2165
      for (Expression_list::const_iterator p = ce->args()->begin();
2166
           p != ce->args()->end();
2167
           ++p)
2168
        vals->push_back(*p);
2169
    }
2170
 
2171
  // Build the struct.
2172
  Expression* constructor =
2173
    Expression::make_struct_composite_literal(this->struct_type_, vals,
2174
                                              location);
2175
 
2176
  // Allocate the initialized struct on the heap.
2177
  constructor = Expression::make_heap_composite(constructor, location);
2178
 
2179
  // Look up the thunk.
2180
  Named_object* named_thunk = gogo->lookup(thunk_name, NULL);
2181
  go_assert(named_thunk != NULL && named_thunk->is_function());
2182
 
2183
  // Build the call.
2184
  Expression* func = Expression::make_func_reference(named_thunk, NULL,
2185
                                                     location);
2186
  Expression_list* params = new Expression_list();
2187
  params->push_back(constructor);
2188
  Call_expression* call = Expression::make_call(func, params, false, location);
2189
 
2190
  // Build the simple go or defer statement.
2191
  Statement* s;
2192
  if (this->classification() == STATEMENT_GO)
2193
    s = Statement::make_go_statement(call, location);
2194
  else if (this->classification() == STATEMENT_DEFER)
2195
    s = Statement::make_defer_statement(call, location);
2196
  else
2197
    go_unreachable();
2198
 
2199
  // The current block should end with the go statement.
2200
  go_assert(block->statements()->size() >= 1);
2201
  go_assert(block->statements()->back() == this);
2202
  block->replace_statement(block->statements()->size() - 1, s);
2203
 
2204
  // We already ran the determine_types pass, so we need to run it now
2205
  // for the new statement.
2206
  s->determine_types();
2207
 
2208
  // Sanity check.
2209
  gogo->check_types_in_block(block);
2210
 
2211
  // Return true to tell the block not to keep looking at statements.
2212
  return true;
2213
}
2214
 
2215
// Set the name to use for thunk parameter N.
2216
 
2217
void
2218
Thunk_statement::thunk_field_param(int n, char* buf, size_t buflen)
2219
{
2220
  snprintf(buf, buflen, "a%d", n);
2221
}
2222
 
2223
// Build a new struct type to hold the parameters for a complicated
2224
// thunk statement.  FNTYPE is the type of the function call.
2225
 
2226
Struct_type*
2227
Thunk_statement::build_struct(Function_type* fntype)
2228
{
2229
  Location location = this->location();
2230
 
2231
  Struct_field_list* fields = new Struct_field_list();
2232
 
2233
  Call_expression* ce = this->call_->call_expression();
2234
  Expression* fn = ce->fn();
2235
 
2236
  if (!this->is_constant_function())
2237
    {
2238
      // The function to call.
2239
      fields->push_back(Struct_field(Typed_identifier("fn", fntype,
2240
                                                      location)));
2241
    }
2242
 
2243
  // If this thunk statement calls a method on an interface, we pass
2244
  // the interface object to the thunk.
2245
  Interface_field_reference_expression* interface_method =
2246
    fn->interface_field_reference_expression();
2247
  if (interface_method != NULL)
2248
    {
2249
      Typed_identifier tid("object", interface_method->expr()->type(),
2250
                           location);
2251
      fields->push_back(Struct_field(tid));
2252
    }
2253
 
2254
  // The predeclared recover function has no argument.  However, we
2255
  // add an argument when building recover thunks.  Handle that here.
2256
  if (ce->is_recover_call())
2257
    {
2258
      fields->push_back(Struct_field(Typed_identifier("can_recover",
2259
                                                      Type::lookup_bool_type(),
2260
                                                      location)));
2261
    }
2262
 
2263
  const Expression_list* args = ce->args();
2264
  if (args != NULL)
2265
    {
2266
      int i = 0;
2267
      for (Expression_list::const_iterator p = args->begin();
2268
           p != args->end();
2269
           ++p, ++i)
2270
        {
2271
          char buf[50];
2272
          this->thunk_field_param(i, buf, sizeof buf);
2273
          fields->push_back(Struct_field(Typed_identifier(buf, (*p)->type(),
2274
                                                          location)));
2275
        }
2276
    }
2277
 
2278
  return Type::make_struct_type(fields, location);
2279
}
2280
 
2281
// Build the thunk we are going to call.  This is a brand new, albeit
2282
// artificial, function.
2283
 
2284
void
2285
Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
2286
{
2287
  Location location = this->location();
2288
 
2289
  Call_expression* ce = this->call_->call_expression();
2290
 
2291
  bool may_call_recover = false;
2292
  if (this->classification() == STATEMENT_DEFER)
2293
    {
2294
      Func_expression* fn = ce->fn()->func_expression();
2295
      if (fn == NULL)
2296
        may_call_recover = true;
2297
      else
2298
        {
2299
          const Named_object* no = fn->named_object();
2300
          if (!no->is_function())
2301
            may_call_recover = true;
2302
          else
2303
            may_call_recover = no->func_value()->calls_recover();
2304
        }
2305
    }
2306
 
2307
  // Build the type of the thunk.  The thunk takes a single parameter,
2308
  // which is a pointer to the special structure we build.
2309
  const char* const parameter_name = "__go_thunk_parameter";
2310
  Typed_identifier_list* thunk_parameters = new Typed_identifier_list();
2311
  Type* pointer_to_struct_type = Type::make_pointer_type(this->struct_type_);
2312
  thunk_parameters->push_back(Typed_identifier(parameter_name,
2313
                                               pointer_to_struct_type,
2314
                                               location));
2315
 
2316
  Typed_identifier_list* thunk_results = NULL;
2317
  if (may_call_recover)
2318
    {
2319
      // When deferring a function which may call recover, add a
2320
      // return value, to disable tail call optimizations which will
2321
      // break the way we check whether recover is permitted.
2322
      thunk_results = new Typed_identifier_list();
2323
      thunk_results->push_back(Typed_identifier("", Type::lookup_bool_type(),
2324
                                                location));
2325
    }
2326
 
2327
  Function_type* thunk_type = Type::make_function_type(NULL, thunk_parameters,
2328
                                                       thunk_results,
2329
                                                       location);
2330
 
2331
  // Start building the thunk.
2332
  Named_object* function = gogo->start_function(thunk_name, thunk_type, true,
2333
                                                location);
2334
 
2335
  gogo->start_block(location);
2336
 
2337
  // For a defer statement, start with a call to
2338
  // __go_set_defer_retaddr.  */
2339
  Label* retaddr_label = NULL;
2340
  if (may_call_recover)
2341
    {
2342
      retaddr_label = gogo->add_label_reference("retaddr", location, false);
2343
      Expression* arg = Expression::make_label_addr(retaddr_label, location);
2344
      Expression* call = Runtime::make_call(Runtime::SET_DEFER_RETADDR,
2345
                                            location, 1, arg);
2346
 
2347
      // This is a hack to prevent the middle-end from deleting the
2348
      // label.
2349
      gogo->start_block(location);
2350
      gogo->add_statement(Statement::make_goto_statement(retaddr_label,
2351
                                                         location));
2352
      Block* then_block = gogo->finish_block(location);
2353
      then_block->determine_types();
2354
 
2355
      Statement* s = Statement::make_if_statement(call, then_block, NULL,
2356
                                                  location);
2357
      s->determine_types();
2358
      gogo->add_statement(s);
2359
    }
2360
 
2361
  // Get a reference to the parameter.
2362
  Named_object* named_parameter = gogo->lookup(parameter_name, NULL);
2363
  go_assert(named_parameter != NULL && named_parameter->is_variable());
2364
 
2365
  // Build the call.  Note that the field names are the same as the
2366
  // ones used in build_struct.
2367
  Expression* thunk_parameter = Expression::make_var_reference(named_parameter,
2368
                                                               location);
2369
  thunk_parameter = Expression::make_unary(OPERATOR_MULT, thunk_parameter,
2370
                                           location);
2371
 
2372
  Interface_field_reference_expression* interface_method =
2373
    ce->fn()->interface_field_reference_expression();
2374
 
2375
  Expression* func_to_call;
2376
  unsigned int next_index;
2377
  if (this->is_constant_function())
2378
    {
2379
      func_to_call = ce->fn();
2380
      next_index = 0;
2381
    }
2382
  else
2383
    {
2384
      func_to_call = Expression::make_field_reference(thunk_parameter,
2385
                                                      0, location);
2386
      next_index = 1;
2387
    }
2388
 
2389
  if (interface_method != NULL)
2390
    {
2391
      // The main program passes the interface object.
2392
      go_assert(next_index == 0);
2393
      Expression* r = Expression::make_field_reference(thunk_parameter, 0,
2394
                                                       location);
2395
      const std::string& name(interface_method->name());
2396
      func_to_call = Expression::make_interface_field_reference(r, name,
2397
                                                                location);
2398
      next_index = 1;
2399
    }
2400
 
2401
  Expression_list* call_params = new Expression_list();
2402
  const Struct_field_list* fields = this->struct_type_->fields();
2403
  Struct_field_list::const_iterator p = fields->begin();
2404
  for (unsigned int i = 0; i < next_index; ++i)
2405
    ++p;
2406
  bool is_recover_call = ce->is_recover_call();
2407
  Expression* recover_arg = NULL;
2408
  for (; p != fields->end(); ++p, ++next_index)
2409
    {
2410
      Expression* thunk_param = Expression::make_var_reference(named_parameter,
2411
                                                               location);
2412
      thunk_param = Expression::make_unary(OPERATOR_MULT, thunk_param,
2413
                                           location);
2414
      Expression* param = Expression::make_field_reference(thunk_param,
2415
                                                           next_index,
2416
                                                           location);
2417
      if (!is_recover_call)
2418
        call_params->push_back(param);
2419
      else
2420
        {
2421
          go_assert(call_params->empty());
2422
          recover_arg = param;
2423
        }
2424
    }
2425
 
2426
  if (call_params->empty())
2427
    {
2428
      delete call_params;
2429
      call_params = NULL;
2430
    }
2431
 
2432
  Call_expression* call = Expression::make_call(func_to_call, call_params,
2433
                                                false, location);
2434
 
2435
  // This call expression was already lowered before entering the
2436
  // thunk statement.  Don't try to lower varargs again, as that will
2437
  // cause confusion for, e.g., method calls which already have a
2438
  // receiver parameter.
2439
  call->set_varargs_are_lowered();
2440
 
2441
  Statement* call_statement = Statement::make_statement(call, true);
2442
 
2443
  gogo->add_statement(call_statement);
2444
 
2445
  // If this is a defer statement, the label comes immediately after
2446
  // the call.
2447
  if (may_call_recover)
2448
    {
2449
      gogo->add_label_definition("retaddr", location);
2450
 
2451
      Expression_list* vals = new Expression_list();
2452
      vals->push_back(Expression::make_boolean(false, location));
2453
      gogo->add_statement(Statement::make_return_statement(vals, location));
2454
    }
2455
 
2456
  Block* b = gogo->finish_block(location);
2457
 
2458
  gogo->add_block(b, location);
2459
 
2460
  gogo->lower_block(function, b);
2461
 
2462
  // We already ran the determine_types pass, so we need to run it
2463
  // just for the call statement now.  The other types are known.
2464
  call_statement->determine_types();
2465
 
2466
  if (may_call_recover || recover_arg != NULL)
2467
    {
2468
      // Dig up the call expression, which may have been changed
2469
      // during lowering.
2470
      go_assert(call_statement->classification() == STATEMENT_EXPRESSION);
2471
      Expression_statement* es =
2472
        static_cast<Expression_statement*>(call_statement);
2473
      Call_expression* ce = es->expr()->call_expression();
2474
      go_assert(ce != NULL);
2475
      if (may_call_recover)
2476
        ce->set_is_deferred();
2477
      if (recover_arg != NULL)
2478
        ce->set_recover_arg(recover_arg);
2479
    }
2480
 
2481
  // That is all the thunk has to do.
2482
  gogo->finish_function(location);
2483
}
2484
 
2485
// Get the function and argument expressions.
2486
 
2487
bool
2488
Thunk_statement::get_fn_and_arg(Expression** pfn, Expression** parg)
2489
{
2490
  if (this->call_->is_error_expression())
2491
    return false;
2492
 
2493
  Call_expression* ce = this->call_->call_expression();
2494
 
2495
  *pfn = ce->fn();
2496
 
2497
  const Expression_list* args = ce->args();
2498
  if (args == NULL || args->empty())
2499
    *parg = Expression::make_nil(this->location());
2500
  else
2501
    {
2502
      go_assert(args->size() == 1);
2503
      *parg = args->front();
2504
    }
2505
 
2506
  return true;
2507
}
2508
 
2509
// Class Go_statement.
2510
 
2511
Bstatement*
2512
Go_statement::do_get_backend(Translate_context* context)
2513
{
2514
  Expression* fn;
2515
  Expression* arg;
2516
  if (!this->get_fn_and_arg(&fn, &arg))
2517
    return context->backend()->error_statement();
2518
 
2519
  Expression* call = Runtime::make_call(Runtime::GO, this->location(), 2,
2520
                                        fn, arg);
2521
  tree call_tree = call->get_tree(context);
2522
  Bexpression* call_bexpr = tree_to_expr(call_tree);
2523
  return context->backend()->expression_statement(call_bexpr);
2524
}
2525
 
2526
// Dump the AST representation for go statement.
2527
 
2528
void
2529
Go_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2530
{
2531
  ast_dump_context->print_indent();
2532
  ast_dump_context->ostream() << "go ";
2533
  ast_dump_context->dump_expression(this->call());
2534
  ast_dump_context->ostream() << std::endl;
2535
}
2536
 
2537
// Make a go statement.
2538
 
2539
Statement*
2540
Statement::make_go_statement(Call_expression* call, Location location)
2541
{
2542
  return new Go_statement(call, location);
2543
}
2544
 
2545
// Class Defer_statement.
2546
 
2547
Bstatement*
2548
Defer_statement::do_get_backend(Translate_context* context)
2549
{
2550
  Expression* fn;
2551
  Expression* arg;
2552
  if (!this->get_fn_and_arg(&fn, &arg))
2553
    return context->backend()->error_statement();
2554
 
2555
  Location loc = this->location();
2556
  Expression* ds = context->function()->func_value()->defer_stack(loc);
2557
 
2558
  Expression* call = Runtime::make_call(Runtime::DEFER, loc, 3,
2559
                                        ds, fn, arg);
2560
  tree call_tree = call->get_tree(context);
2561
  Bexpression* call_bexpr = tree_to_expr(call_tree);
2562
  return context->backend()->expression_statement(call_bexpr);
2563
}
2564
 
2565
// Dump the AST representation for defer statement.
2566
 
2567
void
2568
Defer_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2569
{
2570
  ast_dump_context->print_indent();
2571
  ast_dump_context->ostream() << "defer ";
2572
  ast_dump_context->dump_expression(this->call());
2573
  ast_dump_context->ostream() << std::endl;
2574
}
2575
 
2576
// Make a defer statement.
2577
 
2578
Statement*
2579
Statement::make_defer_statement(Call_expression* call,
2580
                                Location location)
2581
{
2582
  return new Defer_statement(call, location);
2583
}
2584
 
2585
// Class Return_statement.
2586
 
2587
// Traverse assignments.  We treat each return value as a top level
2588
// RHS in an expression.
2589
 
2590
bool
2591
Return_statement::do_traverse_assignments(Traverse_assignments* tassign)
2592
{
2593
  Expression_list* vals = this->vals_;
2594
  if (vals != NULL)
2595
    {
2596
      for (Expression_list::iterator p = vals->begin();
2597
           p != vals->end();
2598
           ++p)
2599
        tassign->value(&*p, true, true);
2600
    }
2601
  return true;
2602
}
2603
 
2604
// Lower a return statement.  If we are returning a function call
2605
// which returns multiple values which match the current function,
2606
// split up the call's results.  If the return statement lists
2607
// explicit values, implement this statement by assigning the values
2608
// to the result variables and change this statement to a naked
2609
// return.  This lets panic/recover work correctly.
2610
 
2611
Statement*
2612
Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
2613
                           Statement_inserter*)
2614
{
2615
  if (this->is_lowered_)
2616
    return this;
2617
 
2618
  Expression_list* vals = this->vals_;
2619
  this->vals_ = NULL;
2620
  this->is_lowered_ = true;
2621
 
2622
  Location loc = this->location();
2623
 
2624
  size_t vals_count = vals == NULL ? 0 : vals->size();
2625
  Function::Results* results = function->func_value()->result_variables();
2626
  size_t results_count = results == NULL ? 0 : results->size();
2627
 
2628
  if (vals_count == 0)
2629
    {
2630
      if (results_count > 0 && !function->func_value()->results_are_named())
2631
        {
2632
          this->report_error(_("not enough arguments to return"));
2633
          return this;
2634
        }
2635
      return this;
2636
    }
2637
 
2638
  if (results_count == 0)
2639
    {
2640
      this->report_error(_("return with value in function "
2641
                           "with no return type"));
2642
      return this;
2643
    }
2644
 
2645
  // If the current function has multiple return values, and we are
2646
  // returning a single call expression, split up the call expression.
2647
  if (results_count > 1
2648
      && vals->size() == 1
2649
      && vals->front()->call_expression() != NULL)
2650
    {
2651
      Call_expression* call = vals->front()->call_expression();
2652
      delete vals;
2653
      vals = new Expression_list;
2654
      for (size_t i = 0; i < results_count; ++i)
2655
        vals->push_back(Expression::make_call_result(call, i));
2656
      vals_count = results_count;
2657
    }
2658
 
2659
  if (vals_count < results_count)
2660
    {
2661
      this->report_error(_("not enough arguments to return"));
2662
      return this;
2663
    }
2664
 
2665
  if (vals_count > results_count)
2666
    {
2667
      this->report_error(_("too many values in return statement"));
2668
      return this;
2669
    }
2670
 
2671
  Block* b = new Block(enclosing, loc);
2672
 
2673
  Expression_list* lhs = new Expression_list();
2674
  Expression_list* rhs = new Expression_list();
2675
 
2676
  Expression_list::const_iterator pe = vals->begin();
2677
  int i = 1;
2678
  for (Function::Results::const_iterator pr = results->begin();
2679
       pr != results->end();
2680
       ++pr, ++pe, ++i)
2681
    {
2682
      Named_object* rv = *pr;
2683
      Expression* e = *pe;
2684
 
2685
      // Check types now so that we give a good error message.  The
2686
      // result type is known.  We determine the expression type
2687
      // early.
2688
 
2689
      Type *rvtype = rv->result_var_value()->type();
2690
      Type_context type_context(rvtype, false);
2691
      e->determine_type(&type_context);
2692
 
2693
      std::string reason;
2694
      bool ok;
2695
      if (this->are_hidden_fields_ok_)
2696
        ok = Type::are_assignable_hidden_ok(rvtype, e->type(), &reason);
2697
      else
2698
        ok = Type::are_assignable(rvtype, e->type(), &reason);
2699
      if (ok)
2700
        {
2701
          Expression* ve = Expression::make_var_reference(rv, e->location());
2702
          lhs->push_back(ve);
2703
          rhs->push_back(e);
2704
        }
2705
      else
2706
        {
2707
          if (reason.empty())
2708
            error_at(e->location(), "incompatible type for return value %d", i);
2709
          else
2710
            error_at(e->location(),
2711
                     "incompatible type for return value %d (%s)",
2712
                     i, reason.c_str());
2713
        }
2714
    }
2715
  go_assert(lhs->size() == rhs->size());
2716
 
2717
  if (lhs->empty())
2718
    ;
2719
  else if (lhs->size() == 1)
2720
    {
2721
      Statement* s = Statement::make_assignment(lhs->front(), rhs->front(),
2722
                                                loc);
2723
      if (this->are_hidden_fields_ok_)
2724
        {
2725
          Assignment_statement* as = static_cast<Assignment_statement*>(s);
2726
          as->set_hidden_fields_are_ok();
2727
        }
2728
      b->add_statement(s);
2729
      delete lhs;
2730
      delete rhs;
2731
    }
2732
  else
2733
    {
2734
      Statement* s = Statement::make_tuple_assignment(lhs, rhs, loc);
2735
      if (this->are_hidden_fields_ok_)
2736
        {
2737
          Tuple_assignment_statement* tas =
2738
            static_cast<Tuple_assignment_statement*>(s);
2739
          tas->set_hidden_fields_are_ok();
2740
        }
2741
      b->add_statement(s);
2742
    }
2743
 
2744
  b->add_statement(this);
2745
 
2746
  delete vals;
2747
 
2748
  return Statement::make_block_statement(b, loc);
2749
}
2750
 
2751
// Convert a return statement to the backend representation.
2752
 
2753
Bstatement*
2754
Return_statement::do_get_backend(Translate_context* context)
2755
{
2756
  Location loc = this->location();
2757
 
2758
  Function* function = context->function()->func_value();
2759
  tree fndecl = function->get_decl();
2760
 
2761
  Function::Results* results = function->result_variables();
2762
  std::vector<Bexpression*> retvals;
2763
  if (results != NULL && !results->empty())
2764
    {
2765
      retvals.reserve(results->size());
2766
      for (Function::Results::const_iterator p = results->begin();
2767
           p != results->end();
2768
           p++)
2769
        {
2770
          Expression* vr = Expression::make_var_reference(*p, loc);
2771
          retvals.push_back(tree_to_expr(vr->get_tree(context)));
2772
        }
2773
    }
2774
 
2775
  return context->backend()->return_statement(tree_to_function(fndecl),
2776
                                              retvals, loc);
2777
}
2778
 
2779
// Dump the AST representation for a return statement.
2780
 
2781
void
2782
Return_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2783
{
2784
  ast_dump_context->print_indent();
2785
  ast_dump_context->ostream() << "return " ;
2786
  ast_dump_context->dump_expression_list(this->vals_);
2787
  ast_dump_context->ostream() << std::endl;
2788
}
2789
 
2790
// Make a return statement.
2791
 
2792
Return_statement*
2793
Statement::make_return_statement(Expression_list* vals,
2794
                                 Location location)
2795
{
2796
  return new Return_statement(vals, location);
2797
}
2798
 
2799
// A break or continue statement.
2800
 
2801
class Bc_statement : public Statement
2802
{
2803
 public:
2804
  Bc_statement(bool is_break, Unnamed_label* label, Location location)
2805
    : Statement(STATEMENT_BREAK_OR_CONTINUE, location),
2806
      label_(label), is_break_(is_break)
2807
  { }
2808
 
2809
  bool
2810
  is_break() const
2811
  { return this->is_break_; }
2812
 
2813
 protected:
2814
  int
2815
  do_traverse(Traverse*)
2816
  { return TRAVERSE_CONTINUE; }
2817
 
2818
  bool
2819
  do_may_fall_through() const
2820
  { return false; }
2821
 
2822
  Bstatement*
2823
  do_get_backend(Translate_context* context)
2824
  { return this->label_->get_goto(context, this->location()); }
2825
 
2826
  void
2827
  do_dump_statement(Ast_dump_context*) const;
2828
 
2829
 private:
2830
  // The label that this branches to.
2831
  Unnamed_label* label_;
2832
  // True if this is "break", false if it is "continue".
2833
  bool is_break_;
2834
};
2835
 
2836
// Dump the AST representation for a break/continue statement
2837
 
2838
void
2839
Bc_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2840
{
2841
  ast_dump_context->print_indent();
2842
  ast_dump_context->ostream() << (this->is_break_ ? "break" : "continue");
2843
  if (this->label_ != NULL)
2844
    {
2845
      ast_dump_context->ostream() << " ";
2846
      ast_dump_context->dump_label_name(this->label_);
2847
    }
2848
  ast_dump_context->ostream() << std::endl;
2849
}
2850
 
2851
// Make a break statement.
2852
 
2853
Statement*
2854
Statement::make_break_statement(Unnamed_label* label, Location location)
2855
{
2856
  return new Bc_statement(true, label, location);
2857
}
2858
 
2859
// Make a continue statement.
2860
 
2861
Statement*
2862
Statement::make_continue_statement(Unnamed_label* label,
2863
                                   Location location)
2864
{
2865
  return new Bc_statement(false, label, location);
2866
}
2867
 
2868
// A goto statement.
2869
 
2870
class Goto_statement : public Statement
2871
{
2872
 public:
2873
  Goto_statement(Label* label, Location location)
2874
    : Statement(STATEMENT_GOTO, location),
2875
      label_(label)
2876
  { }
2877
 
2878
 protected:
2879
  int
2880
  do_traverse(Traverse*)
2881
  { return TRAVERSE_CONTINUE; }
2882
 
2883
  void
2884
  do_check_types(Gogo*);
2885
 
2886
  bool
2887
  do_may_fall_through() const
2888
  { return false; }
2889
 
2890
  Bstatement*
2891
  do_get_backend(Translate_context*);
2892
 
2893
  void
2894
  do_dump_statement(Ast_dump_context*) const;
2895
 
2896
 private:
2897
  Label* label_;
2898
};
2899
 
2900
// Check types for a label.  There aren't any types per se, but we use
2901
// this to give an error if the label was never defined.
2902
 
2903
void
2904
Goto_statement::do_check_types(Gogo*)
2905
{
2906
  if (!this->label_->is_defined())
2907
    {
2908
      error_at(this->location(), "reference to undefined label %qs",
2909
               Gogo::message_name(this->label_->name()).c_str());
2910
      this->set_is_error();
2911
    }
2912
}
2913
 
2914
// Convert the goto statement to the backend representation.
2915
 
2916
Bstatement*
2917
Goto_statement::do_get_backend(Translate_context* context)
2918
{
2919
  Blabel* blabel = this->label_->get_backend_label(context);
2920
  return context->backend()->goto_statement(blabel, this->location());
2921
}
2922
 
2923
// Dump the AST representation for a goto statement.
2924
 
2925
void
2926
Goto_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
2927
{
2928
  ast_dump_context->print_indent();
2929
  ast_dump_context->ostream() << "goto " << this->label_->name() << std::endl;
2930
}
2931
 
2932
// Make a goto statement.
2933
 
2934
Statement*
2935
Statement::make_goto_statement(Label* label, Location location)
2936
{
2937
  return new Goto_statement(label, location);
2938
}
2939
 
2940
// A goto statement to an unnamed label.
2941
 
2942
class Goto_unnamed_statement : public Statement
2943
{
2944
 public:
2945
  Goto_unnamed_statement(Unnamed_label* label, Location location)
2946
    : Statement(STATEMENT_GOTO_UNNAMED, location),
2947
      label_(label)
2948
  { }
2949
 
2950
 protected:
2951
  int
2952
  do_traverse(Traverse*)
2953
  { return TRAVERSE_CONTINUE; }
2954
 
2955
  bool
2956
  do_may_fall_through() const
2957
  { return false; }
2958
 
2959
  Bstatement*
2960
  do_get_backend(Translate_context* context)
2961
  { return this->label_->get_goto(context, this->location()); }
2962
 
2963
  void
2964
  do_dump_statement(Ast_dump_context*) const;
2965
 
2966
 private:
2967
  Unnamed_label* label_;
2968
};
2969
 
2970
// Dump the AST representation for an unnamed goto statement
2971
 
2972
void
2973
Goto_unnamed_statement::do_dump_statement(
2974
    Ast_dump_context* ast_dump_context) const
2975
{
2976
  ast_dump_context->print_indent();
2977
  ast_dump_context->ostream() << "goto ";
2978
  ast_dump_context->dump_label_name(this->label_);
2979
  ast_dump_context->ostream() << std::endl;
2980
}
2981
 
2982
// Make a goto statement to an unnamed label.
2983
 
2984
Statement*
2985
Statement::make_goto_unnamed_statement(Unnamed_label* label,
2986
                                       Location location)
2987
{
2988
  return new Goto_unnamed_statement(label, location);
2989
}
2990
 
2991
// Class Label_statement.
2992
 
2993
// Traversal.
2994
 
2995
int
2996
Label_statement::do_traverse(Traverse*)
2997
{
2998
  return TRAVERSE_CONTINUE;
2999
}
3000
 
3001
// Return the backend representation of the statement defining this
3002
// label.
3003
 
3004
Bstatement*
3005
Label_statement::do_get_backend(Translate_context* context)
3006
{
3007
  Blabel* blabel = this->label_->get_backend_label(context);
3008
  return context->backend()->label_definition_statement(blabel);
3009
}
3010
 
3011
// Dump the AST for a label definition statement.
3012
 
3013
void
3014
Label_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3015
{
3016
  ast_dump_context->print_indent();
3017
  ast_dump_context->ostream() << this->label_->name() << ":" << std::endl;
3018
}
3019
 
3020
// Make a label statement.
3021
 
3022
Statement*
3023
Statement::make_label_statement(Label* label, Location location)
3024
{
3025
  return new Label_statement(label, location);
3026
}
3027
 
3028
// An unnamed label statement.
3029
 
3030
class Unnamed_label_statement : public Statement
3031
{
3032
 public:
3033
  Unnamed_label_statement(Unnamed_label* label)
3034
    : Statement(STATEMENT_UNNAMED_LABEL, label->location()),
3035
      label_(label)
3036
  { }
3037
 
3038
 protected:
3039
  int
3040
  do_traverse(Traverse*)
3041
  { return TRAVERSE_CONTINUE; }
3042
 
3043
  Bstatement*
3044
  do_get_backend(Translate_context* context)
3045
  { return this->label_->get_definition(context); }
3046
 
3047
  void
3048
  do_dump_statement(Ast_dump_context*) const;
3049
 
3050
 private:
3051
  // The label.
3052
  Unnamed_label* label_;
3053
};
3054
 
3055
// Dump the AST representation for an unnamed label definition statement.
3056
 
3057
void
3058
Unnamed_label_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
3059
    const
3060
{
3061
  ast_dump_context->print_indent();
3062
  ast_dump_context->dump_label_name(this->label_);
3063
  ast_dump_context->ostream() << ":" << std::endl;
3064
}
3065
 
3066
// Make an unnamed label statement.
3067
 
3068
Statement*
3069
Statement::make_unnamed_label_statement(Unnamed_label* label)
3070
{
3071
  return new Unnamed_label_statement(label);
3072
}
3073
 
3074
// An if statement.
3075
 
3076
class If_statement : public Statement
3077
{
3078
 public:
3079
  If_statement(Expression* cond, Block* then_block, Block* else_block,
3080
               Location location)
3081
    : Statement(STATEMENT_IF, location),
3082
      cond_(cond), then_block_(then_block), else_block_(else_block)
3083
  { }
3084
 
3085
 protected:
3086
  int
3087
  do_traverse(Traverse*);
3088
 
3089
  void
3090
  do_determine_types();
3091
 
3092
  void
3093
  do_check_types(Gogo*);
3094
 
3095
  bool
3096
  do_may_fall_through() const;
3097
 
3098
  Bstatement*
3099
  do_get_backend(Translate_context*);
3100
 
3101
  void
3102
  do_dump_statement(Ast_dump_context*) const;
3103
 
3104
 private:
3105
  Expression* cond_;
3106
  Block* then_block_;
3107
  Block* else_block_;
3108
};
3109
 
3110
// Traversal.
3111
 
3112
int
3113
If_statement::do_traverse(Traverse* traverse)
3114
{
3115
  if (this->traverse_expression(traverse, &this->cond_) == TRAVERSE_EXIT
3116
      || this->then_block_->traverse(traverse) == TRAVERSE_EXIT)
3117
    return TRAVERSE_EXIT;
3118
  if (this->else_block_ != NULL)
3119
    {
3120
      if (this->else_block_->traverse(traverse) == TRAVERSE_EXIT)
3121
        return TRAVERSE_EXIT;
3122
    }
3123
  return TRAVERSE_CONTINUE;
3124
}
3125
 
3126
void
3127
If_statement::do_determine_types()
3128
{
3129
  Type_context context(Type::lookup_bool_type(), false);
3130
  this->cond_->determine_type(&context);
3131
  this->then_block_->determine_types();
3132
  if (this->else_block_ != NULL)
3133
    this->else_block_->determine_types();
3134
}
3135
 
3136
// Check types.
3137
 
3138
void
3139
If_statement::do_check_types(Gogo*)
3140
{
3141
  Type* type = this->cond_->type();
3142
  if (type->is_error())
3143
    this->set_is_error();
3144
  else if (!type->is_boolean_type())
3145
    this->report_error(_("expected boolean expression"));
3146
}
3147
 
3148
// Whether the overall statement may fall through.
3149
 
3150
bool
3151
If_statement::do_may_fall_through() const
3152
{
3153
  return (this->else_block_ == NULL
3154
          || this->then_block_->may_fall_through()
3155
          || this->else_block_->may_fall_through());
3156
}
3157
 
3158
// Get the backend representation.
3159
 
3160
Bstatement*
3161
If_statement::do_get_backend(Translate_context* context)
3162
{
3163
  go_assert(this->cond_->type()->is_boolean_type()
3164
             || this->cond_->type()->is_error());
3165
  tree cond_tree = this->cond_->get_tree(context);
3166
  Bexpression* cond_expr = tree_to_expr(cond_tree);
3167
  Bblock* then_block = this->then_block_->get_backend(context);
3168
  Bblock* else_block = (this->else_block_ == NULL
3169
                        ? NULL
3170
                        : this->else_block_->get_backend(context));
3171
  return context->backend()->if_statement(cond_expr, then_block,
3172
                                          else_block, this->location());
3173
}
3174
 
3175
// Dump the AST representation for an if statement
3176
 
3177
void
3178
If_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3179
{
3180
  ast_dump_context->print_indent();
3181
  ast_dump_context->ostream() << "if ";
3182
  ast_dump_context->dump_expression(this->cond_);
3183
  ast_dump_context->ostream() << std::endl;
3184
  if (ast_dump_context->dump_subblocks())
3185
    {
3186
      ast_dump_context->dump_block(this->then_block_);
3187
      if (this->else_block_ != NULL)
3188
        {
3189
          ast_dump_context->print_indent();
3190
          ast_dump_context->ostream() << "else" << std::endl;
3191
          ast_dump_context->dump_block(this->else_block_);
3192
        }
3193
    }
3194
}
3195
 
3196
// Make an if statement.
3197
 
3198
Statement*
3199
Statement::make_if_statement(Expression* cond, Block* then_block,
3200
                             Block* else_block, Location location)
3201
{
3202
  return new If_statement(cond, then_block, else_block, location);
3203
}
3204
 
3205
// Class Case_clauses::Hash_integer_value.
3206
 
3207
class Case_clauses::Hash_integer_value
3208
{
3209
 public:
3210
  size_t
3211
  operator()(Expression*) const;
3212
};
3213
 
3214
size_t
3215
Case_clauses::Hash_integer_value::operator()(Expression* pe) const
3216
{
3217
  Type* itype;
3218
  mpz_t ival;
3219
  mpz_init(ival);
3220
  if (!pe->integer_constant_value(true, ival, &itype))
3221
    go_unreachable();
3222
  size_t ret = mpz_get_ui(ival);
3223
  mpz_clear(ival);
3224
  return ret;
3225
}
3226
 
3227
// Class Case_clauses::Eq_integer_value.
3228
 
3229
class Case_clauses::Eq_integer_value
3230
{
3231
 public:
3232
  bool
3233
  operator()(Expression*, Expression*) const;
3234
};
3235
 
3236
bool
3237
Case_clauses::Eq_integer_value::operator()(Expression* a, Expression* b) const
3238
{
3239
  Type* atype;
3240
  Type* btype;
3241
  mpz_t aval;
3242
  mpz_t bval;
3243
  mpz_init(aval);
3244
  mpz_init(bval);
3245
  if (!a->integer_constant_value(true, aval, &atype)
3246
      || !b->integer_constant_value(true, bval, &btype))
3247
    go_unreachable();
3248
  bool ret = mpz_cmp(aval, bval) == 0;
3249
  mpz_clear(aval);
3250
  mpz_clear(bval);
3251
  return ret;
3252
}
3253
 
3254
// Class Case_clauses::Case_clause.
3255
 
3256
// Traversal.
3257
 
3258
int
3259
Case_clauses::Case_clause::traverse(Traverse* traverse)
3260
{
3261
  if (this->cases_ != NULL
3262
      && (traverse->traverse_mask()
3263
          & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
3264
    {
3265
      if (this->cases_->traverse(traverse) == TRAVERSE_EXIT)
3266
        return TRAVERSE_EXIT;
3267
    }
3268
  if (this->statements_ != NULL)
3269
    {
3270
      if (this->statements_->traverse(traverse) == TRAVERSE_EXIT)
3271
        return TRAVERSE_EXIT;
3272
    }
3273
  return TRAVERSE_CONTINUE;
3274
}
3275
 
3276
// Check whether all the case expressions are integer constants.
3277
 
3278
bool
3279
Case_clauses::Case_clause::is_constant() const
3280
{
3281
  if (this->cases_ != NULL)
3282
    {
3283
      for (Expression_list::const_iterator p = this->cases_->begin();
3284
           p != this->cases_->end();
3285
           ++p)
3286
        if (!(*p)->is_constant() || (*p)->type()->integer_type() == NULL)
3287
          return false;
3288
    }
3289
  return true;
3290
}
3291
 
3292
// Lower a case clause for a nonconstant switch.  VAL_TEMP is the
3293
// value we are switching on; it may be NULL.  If START_LABEL is not
3294
// NULL, it goes at the start of the statements, after the condition
3295
// test.  We branch to FINISH_LABEL at the end of the statements.
3296
 
3297
void
3298
Case_clauses::Case_clause::lower(Block* b, Temporary_statement* val_temp,
3299
                                 Unnamed_label* start_label,
3300
                                 Unnamed_label* finish_label) const
3301
{
3302
  Location loc = this->location_;
3303
  Unnamed_label* next_case_label;
3304
  if (this->cases_ == NULL || this->cases_->empty())
3305
    {
3306
      go_assert(this->is_default_);
3307
      next_case_label = NULL;
3308
    }
3309
  else
3310
    {
3311
      Expression* cond = NULL;
3312
 
3313
      for (Expression_list::const_iterator p = this->cases_->begin();
3314
           p != this->cases_->end();
3315
           ++p)
3316
        {
3317
          Expression* this_cond;
3318
          if (val_temp == NULL)
3319
            this_cond = *p;
3320
          else
3321
            {
3322
              Expression* ref = Expression::make_temporary_reference(val_temp,
3323
                                                                     loc);
3324
              this_cond = Expression::make_binary(OPERATOR_EQEQ, ref, *p, loc);
3325
            }
3326
 
3327
          if (cond == NULL)
3328
            cond = this_cond;
3329
          else
3330
            cond = Expression::make_binary(OPERATOR_OROR, cond, this_cond, loc);
3331
        }
3332
 
3333
      Block* then_block = new Block(b, loc);
3334
      next_case_label = new Unnamed_label(Linemap::unknown_location());
3335
      Statement* s = Statement::make_goto_unnamed_statement(next_case_label,
3336
                                                            loc);
3337
      then_block->add_statement(s);
3338
 
3339
      // if !COND { goto NEXT_CASE_LABEL }
3340
      cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
3341
      s = Statement::make_if_statement(cond, then_block, NULL, loc);
3342
      b->add_statement(s);
3343
    }
3344
 
3345
  if (start_label != NULL)
3346
    b->add_statement(Statement::make_unnamed_label_statement(start_label));
3347
 
3348
  if (this->statements_ != NULL)
3349
    b->add_statement(Statement::make_block_statement(this->statements_, loc));
3350
 
3351
  Statement* s = Statement::make_goto_unnamed_statement(finish_label, loc);
3352
  b->add_statement(s);
3353
 
3354
  if (next_case_label != NULL)
3355
    b->add_statement(Statement::make_unnamed_label_statement(next_case_label));
3356
}
3357
 
3358
// Determine types.
3359
 
3360
void
3361
Case_clauses::Case_clause::determine_types(Type* type)
3362
{
3363
  if (this->cases_ != NULL)
3364
    {
3365
      Type_context case_context(type, false);
3366
      for (Expression_list::iterator p = this->cases_->begin();
3367
           p != this->cases_->end();
3368
           ++p)
3369
        (*p)->determine_type(&case_context);
3370
    }
3371
  if (this->statements_ != NULL)
3372
    this->statements_->determine_types();
3373
}
3374
 
3375
// Check types.  Returns false if there was an error.
3376
 
3377
bool
3378
Case_clauses::Case_clause::check_types(Type* type)
3379
{
3380
  if (this->cases_ != NULL)
3381
    {
3382
      for (Expression_list::iterator p = this->cases_->begin();
3383
           p != this->cases_->end();
3384
           ++p)
3385
        {
3386
          if (!Type::are_assignable(type, (*p)->type(), NULL)
3387
              && !Type::are_assignable((*p)->type(), type, NULL))
3388
            {
3389
              error_at((*p)->location(),
3390
                       "type mismatch between switch value and case clause");
3391
              return false;
3392
            }
3393
        }
3394
    }
3395
  return true;
3396
}
3397
 
3398
// Return true if this clause may fall through to the following
3399
// statements.  Note that this is not the same as whether the case
3400
// uses the "fallthrough" keyword.
3401
 
3402
bool
3403
Case_clauses::Case_clause::may_fall_through() const
3404
{
3405
  if (this->statements_ == NULL)
3406
    return true;
3407
  return this->statements_->may_fall_through();
3408
}
3409
 
3410
// Convert the case values and statements to the backend
3411
// representation.  BREAK_LABEL is the label which break statements
3412
// should branch to.  CASE_CONSTANTS is used to detect duplicate
3413
// constants.  *CASES should be passed as an empty vector; the values
3414
// for this case will be added to it.  If this is the default case,
3415
// *CASES will remain empty.  This returns the statement to execute if
3416
// one of these cases is selected.
3417
 
3418
Bstatement*
3419
Case_clauses::Case_clause::get_backend(Translate_context* context,
3420
                                       Unnamed_label* break_label,
3421
                                       Case_constants* case_constants,
3422
                                       std::vector<Bexpression*>* cases) const
3423
{
3424
  if (this->cases_ != NULL)
3425
    {
3426
      go_assert(!this->is_default_);
3427
      for (Expression_list::const_iterator p = this->cases_->begin();
3428
           p != this->cases_->end();
3429
           ++p)
3430
        {
3431
          Expression* e = *p;
3432
          if (e->classification() != Expression::EXPRESSION_INTEGER)
3433
            {
3434
              Type* itype;
3435
              mpz_t ival;
3436
              mpz_init(ival);
3437
              if (!(*p)->integer_constant_value(true, ival, &itype))
3438
                {
3439
                  // Something went wrong.  This can happen with a
3440
                  // negative constant and an unsigned switch value.
3441
                  go_assert(saw_errors());
3442
                  continue;
3443
                }
3444
              go_assert(itype != NULL);
3445
              e = Expression::make_integer(&ival, itype, e->location());
3446
              mpz_clear(ival);
3447
            }
3448
 
3449
          std::pair<Case_constants::iterator, bool> ins =
3450
            case_constants->insert(e);
3451
          if (!ins.second)
3452
            {
3453
              // Value was already present.
3454
              error_at(this->location_, "duplicate case in switch");
3455
              continue;
3456
            }
3457
 
3458
          tree case_tree = e->get_tree(context);
3459
          Bexpression* case_expr = tree_to_expr(case_tree);
3460
          cases->push_back(case_expr);
3461
        }
3462
    }
3463
 
3464
  Bstatement* statements;
3465
  if (this->statements_ == NULL)
3466
    statements = NULL;
3467
  else
3468
    {
3469
      Bblock* bblock = this->statements_->get_backend(context);
3470
      statements = context->backend()->block_statement(bblock);
3471
    }
3472
 
3473
  Bstatement* break_stat;
3474
  if (this->is_fallthrough_)
3475
    break_stat = NULL;
3476
  else
3477
    break_stat = break_label->get_goto(context, this->location_);
3478
 
3479
  if (statements == NULL)
3480
    return break_stat;
3481
  else if (break_stat == NULL)
3482
    return statements;
3483
  else
3484
    return context->backend()->compound_statement(statements, break_stat);
3485
}
3486
 
3487
// Dump the AST representation for a case clause
3488
 
3489
void
3490
Case_clauses::Case_clause::dump_clause(Ast_dump_context* ast_dump_context)
3491
    const
3492
{
3493
  ast_dump_context->print_indent();
3494
  if (this->is_default_)
3495
    {
3496
      ast_dump_context->ostream() << "default:";
3497
    }
3498
  else
3499
    {
3500
      ast_dump_context->ostream() << "case ";
3501
      ast_dump_context->dump_expression_list(this->cases_);
3502
      ast_dump_context->ostream() << ":" ;
3503
    }
3504
  ast_dump_context->dump_block(this->statements_);
3505
  if (this->is_fallthrough_)
3506
    {
3507
      ast_dump_context->print_indent();
3508
      ast_dump_context->ostream() <<  " (fallthrough)" << std::endl;
3509
    }
3510
}
3511
 
3512
// Class Case_clauses.
3513
 
3514
// Traversal.
3515
 
3516
int
3517
Case_clauses::traverse(Traverse* traverse)
3518
{
3519
  for (Clauses::iterator p = this->clauses_.begin();
3520
       p != this->clauses_.end();
3521
       ++p)
3522
    {
3523
      if (p->traverse(traverse) == TRAVERSE_EXIT)
3524
        return TRAVERSE_EXIT;
3525
    }
3526
  return TRAVERSE_CONTINUE;
3527
}
3528
 
3529
// Check whether all the case expressions are constant.
3530
 
3531
bool
3532
Case_clauses::is_constant() const
3533
{
3534
  for (Clauses::const_iterator p = this->clauses_.begin();
3535
       p != this->clauses_.end();
3536
       ++p)
3537
    if (!p->is_constant())
3538
      return false;
3539
  return true;
3540
}
3541
 
3542
// Lower case clauses for a nonconstant switch.
3543
 
3544
void
3545
Case_clauses::lower(Block* b, Temporary_statement* val_temp,
3546
                    Unnamed_label* break_label) const
3547
{
3548
  // The default case.
3549
  const Case_clause* default_case = NULL;
3550
 
3551
  // The label for the fallthrough of the previous case.
3552
  Unnamed_label* last_fallthrough_label = NULL;
3553
 
3554
  // The label for the start of the default case.  This is used if the
3555
  // case before the default case falls through.
3556
  Unnamed_label* default_start_label = NULL;
3557
 
3558
  // The label for the end of the default case.  This normally winds
3559
  // up as BREAK_LABEL, but it will be different if the default case
3560
  // falls through.
3561
  Unnamed_label* default_finish_label = NULL;
3562
 
3563
  for (Clauses::const_iterator p = this->clauses_.begin();
3564
       p != this->clauses_.end();
3565
       ++p)
3566
    {
3567
      // The label to use for the start of the statements for this
3568
      // case.  This is NULL unless the previous case falls through.
3569
      Unnamed_label* start_label = last_fallthrough_label;
3570
 
3571
      // The label to jump to after the end of the statements for this
3572
      // case.
3573
      Unnamed_label* finish_label = break_label;
3574
 
3575
      last_fallthrough_label = NULL;
3576
      if (p->is_fallthrough() && p + 1 != this->clauses_.end())
3577
        {
3578
          finish_label = new Unnamed_label(p->location());
3579
          last_fallthrough_label = finish_label;
3580
        }
3581
 
3582
      if (!p->is_default())
3583
        p->lower(b, val_temp, start_label, finish_label);
3584
      else
3585
        {
3586
          // We have to move the default case to the end, so that we
3587
          // only use it if all the other tests fail.
3588
          default_case = &*p;
3589
          default_start_label = start_label;
3590
          default_finish_label = finish_label;
3591
        }
3592
    }
3593
 
3594
  if (default_case != NULL)
3595
    default_case->lower(b, val_temp, default_start_label,
3596
                        default_finish_label);
3597
}
3598
 
3599
// Determine types.
3600
 
3601
void
3602
Case_clauses::determine_types(Type* type)
3603
{
3604
  for (Clauses::iterator p = this->clauses_.begin();
3605
       p != this->clauses_.end();
3606
       ++p)
3607
    p->determine_types(type);
3608
}
3609
 
3610
// Check types.  Returns false if there was an error.
3611
 
3612
bool
3613
Case_clauses::check_types(Type* type)
3614
{
3615
  bool ret = true;
3616
  for (Clauses::iterator p = this->clauses_.begin();
3617
       p != this->clauses_.end();
3618
       ++p)
3619
    {
3620
      if (!p->check_types(type))
3621
        ret = false;
3622
    }
3623
  return ret;
3624
}
3625
 
3626
// Return true if these clauses may fall through to the statements
3627
// following the switch statement.
3628
 
3629
bool
3630
Case_clauses::may_fall_through() const
3631
{
3632
  bool found_default = false;
3633
  for (Clauses::const_iterator p = this->clauses_.begin();
3634
       p != this->clauses_.end();
3635
       ++p)
3636
    {
3637
      if (p->may_fall_through() && !p->is_fallthrough())
3638
        return true;
3639
      if (p->is_default())
3640
        found_default = true;
3641
    }
3642
  return !found_default;
3643
}
3644
 
3645
// Convert the cases to the backend representation.  This sets
3646
// *ALL_CASES and *ALL_STATEMENTS.
3647
 
3648
void
3649
Case_clauses::get_backend(Translate_context* context,
3650
                          Unnamed_label* break_label,
3651
                          std::vector<std::vector<Bexpression*> >* all_cases,
3652
                          std::vector<Bstatement*>* all_statements) const
3653
{
3654
  Case_constants case_constants;
3655
 
3656
  size_t c = this->clauses_.size();
3657
  all_cases->resize(c);
3658
  all_statements->resize(c);
3659
 
3660
  size_t i = 0;
3661
  for (Clauses::const_iterator p = this->clauses_.begin();
3662
       p != this->clauses_.end();
3663
       ++p, ++i)
3664
    {
3665
      std::vector<Bexpression*> cases;
3666
      Bstatement* stat = p->get_backend(context, break_label, &case_constants,
3667
                                        &cases);
3668
      (*all_cases)[i].swap(cases);
3669
      (*all_statements)[i] = stat;
3670
    }
3671
}
3672
 
3673
// Dump the AST representation for case clauses (from a switch statement)
3674
 
3675
void
3676
Case_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
3677
{
3678
  for (Clauses::const_iterator p = this->clauses_.begin();
3679
       p != this->clauses_.end();
3680
       ++p)
3681
    p->dump_clause(ast_dump_context);
3682
}
3683
 
3684
// A constant switch statement.  A Switch_statement is lowered to this
3685
// when all the cases are constants.
3686
 
3687
class Constant_switch_statement : public Statement
3688
{
3689
 public:
3690
  Constant_switch_statement(Expression* val, Case_clauses* clauses,
3691
                            Unnamed_label* break_label,
3692
                            Location location)
3693
    : Statement(STATEMENT_CONSTANT_SWITCH, location),
3694
      val_(val), clauses_(clauses), break_label_(break_label)
3695
  { }
3696
 
3697
 protected:
3698
  int
3699
  do_traverse(Traverse*);
3700
 
3701
  void
3702
  do_determine_types();
3703
 
3704
  void
3705
  do_check_types(Gogo*);
3706
 
3707
  bool
3708
  do_may_fall_through() const;
3709
 
3710
  Bstatement*
3711
  do_get_backend(Translate_context*);
3712
 
3713
  void
3714
  do_dump_statement(Ast_dump_context*) const;
3715
 
3716
 private:
3717
  // The value to switch on.
3718
  Expression* val_;
3719
  // The case clauses.
3720
  Case_clauses* clauses_;
3721
  // The break label, if needed.
3722
  Unnamed_label* break_label_;
3723
};
3724
 
3725
// Traversal.
3726
 
3727
int
3728
Constant_switch_statement::do_traverse(Traverse* traverse)
3729
{
3730
  if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
3731
    return TRAVERSE_EXIT;
3732
  return this->clauses_->traverse(traverse);
3733
}
3734
 
3735
// Determine types.
3736
 
3737
void
3738
Constant_switch_statement::do_determine_types()
3739
{
3740
  this->val_->determine_type_no_context();
3741
  this->clauses_->determine_types(this->val_->type());
3742
}
3743
 
3744
// Check types.
3745
 
3746
void
3747
Constant_switch_statement::do_check_types(Gogo*)
3748
{
3749
  if (!this->clauses_->check_types(this->val_->type()))
3750
    this->set_is_error();
3751
}
3752
 
3753
// Return whether this switch may fall through.
3754
 
3755
bool
3756
Constant_switch_statement::do_may_fall_through() const
3757
{
3758
  if (this->clauses_ == NULL)
3759
    return true;
3760
 
3761
  // If we have a break label, then some case needed it.  That implies
3762
  // that the switch statement as a whole can fall through.
3763
  if (this->break_label_ != NULL)
3764
    return true;
3765
 
3766
  return this->clauses_->may_fall_through();
3767
}
3768
 
3769
// Convert to GENERIC.
3770
 
3771
Bstatement*
3772
Constant_switch_statement::do_get_backend(Translate_context* context)
3773
{
3774
  tree switch_val_tree = this->val_->get_tree(context);
3775
  Bexpression* switch_val_expr = tree_to_expr(switch_val_tree);
3776
 
3777
  Unnamed_label* break_label = this->break_label_;
3778
  if (break_label == NULL)
3779
    break_label = new Unnamed_label(this->location());
3780
 
3781
  std::vector<std::vector<Bexpression*> > all_cases;
3782
  std::vector<Bstatement*> all_statements;
3783
  this->clauses_->get_backend(context, break_label, &all_cases,
3784
                              &all_statements);
3785
 
3786
  Bstatement* switch_statement;
3787
  switch_statement = context->backend()->switch_statement(switch_val_expr,
3788
                                                          all_cases,
3789
                                                          all_statements,
3790
                                                          this->location());
3791
  Bstatement* ldef = break_label->get_definition(context);
3792
  return context->backend()->compound_statement(switch_statement, ldef);
3793
}
3794
 
3795
// Dump the AST representation for a constant switch statement.
3796
 
3797
void
3798
Constant_switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
3799
    const
3800
{
3801
  ast_dump_context->print_indent();
3802
  ast_dump_context->ostream() << "switch ";
3803
  ast_dump_context->dump_expression(this->val_);
3804
 
3805
  if (ast_dump_context->dump_subblocks())
3806
    {
3807
      ast_dump_context->ostream() << " {" << std::endl;
3808
      this->clauses_->dump_clauses(ast_dump_context);
3809
      ast_dump_context->ostream() << "}";
3810
    }
3811
 
3812
   ast_dump_context->ostream() << std::endl;
3813
}
3814
 
3815
// Class Switch_statement.
3816
 
3817
// Traversal.
3818
 
3819
int
3820
Switch_statement::do_traverse(Traverse* traverse)
3821
{
3822
  if (this->val_ != NULL)
3823
    {
3824
      if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
3825
        return TRAVERSE_EXIT;
3826
    }
3827
  return this->clauses_->traverse(traverse);
3828
}
3829
 
3830
// Lower a Switch_statement to a Constant_switch_statement or a series
3831
// of if statements.
3832
 
3833
Statement*
3834
Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
3835
                           Statement_inserter*)
3836
{
3837
  Location loc = this->location();
3838
 
3839
  if (this->val_ != NULL
3840
      && (this->val_->is_error_expression()
3841
          || this->val_->type()->is_error()))
3842
    return Statement::make_error_statement(loc);
3843
 
3844
  if (this->val_ != NULL
3845
      && this->val_->type()->integer_type() != NULL
3846
      && !this->clauses_->empty()
3847
      && this->clauses_->is_constant())
3848
    return new Constant_switch_statement(this->val_, this->clauses_,
3849
                                         this->break_label_, loc);
3850
 
3851
  Block* b = new Block(enclosing, loc);
3852
 
3853
  if (this->clauses_->empty())
3854
    {
3855
      Expression* val = this->val_;
3856
      if (val == NULL)
3857
        val = Expression::make_boolean(true, loc);
3858
      return Statement::make_statement(val, true);
3859
    }
3860
 
3861
  Temporary_statement* val_temp;
3862
  if (this->val_ == NULL)
3863
    val_temp = NULL;
3864
  else
3865
    {
3866
      // var val_temp VAL_TYPE = VAL
3867
      val_temp = Statement::make_temporary(NULL, this->val_, loc);
3868
      b->add_statement(val_temp);
3869
    }
3870
 
3871
  this->clauses_->lower(b, val_temp, this->break_label());
3872
 
3873
  Statement* s = Statement::make_unnamed_label_statement(this->break_label_);
3874
  b->add_statement(s);
3875
 
3876
  return Statement::make_block_statement(b, loc);
3877
}
3878
 
3879
// Return the break label for this switch statement, creating it if
3880
// necessary.
3881
 
3882
Unnamed_label*
3883
Switch_statement::break_label()
3884
{
3885
  if (this->break_label_ == NULL)
3886
    this->break_label_ = new Unnamed_label(this->location());
3887
  return this->break_label_;
3888
}
3889
 
3890
// Dump the AST representation for a switch statement.
3891
 
3892
void
3893
Switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
3894
{
3895
  ast_dump_context->print_indent();
3896
  ast_dump_context->ostream() << "switch ";
3897
  if (this->val_ != NULL)
3898
    {
3899
      ast_dump_context->dump_expression(this->val_);
3900
    }
3901
  if (ast_dump_context->dump_subblocks())
3902
    {
3903
      ast_dump_context->ostream() << " {" << std::endl;
3904
      this->clauses_->dump_clauses(ast_dump_context);
3905
      ast_dump_context->print_indent();
3906
      ast_dump_context->ostream() << "}";
3907
    }
3908
  ast_dump_context->ostream() << std::endl;
3909
}
3910
 
3911
// Make a switch statement.
3912
 
3913
Switch_statement*
3914
Statement::make_switch_statement(Expression* val, Location location)
3915
{
3916
  return new Switch_statement(val, location);
3917
}
3918
 
3919
// Class Type_case_clauses::Type_case_clause.
3920
 
3921
// Traversal.
3922
 
3923
int
3924
Type_case_clauses::Type_case_clause::traverse(Traverse* traverse)
3925
{
3926
  if (!this->is_default_
3927
      && ((traverse->traverse_mask()
3928
           & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
3929
      && Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
3930
    return TRAVERSE_EXIT;
3931
  if (this->statements_ != NULL)
3932
    return this->statements_->traverse(traverse);
3933
  return TRAVERSE_CONTINUE;
3934
}
3935
 
3936
// Lower one clause in a type switch.  Add statements to the block B.
3937
// The type descriptor we are switching on is in DESCRIPTOR_TEMP.
3938
// BREAK_LABEL is the label at the end of the type switch.
3939
// *STMTS_LABEL, if not NULL, is a label to put at the start of the
3940
// statements.
3941
 
3942
void
3943
Type_case_clauses::Type_case_clause::lower(Type* switch_val_type,
3944
                                           Block* b,
3945
                                           Temporary_statement* descriptor_temp,
3946
                                           Unnamed_label* break_label,
3947
                                           Unnamed_label** stmts_label) const
3948
{
3949
  Location loc = this->location_;
3950
 
3951
  Unnamed_label* next_case_label = NULL;
3952
  if (!this->is_default_)
3953
    {
3954
      Type* type = this->type_;
3955
 
3956
      std::string reason;
3957
      if (switch_val_type->interface_type() != NULL
3958
          && !type->is_nil_constant_as_type()
3959
          && type->interface_type() == NULL
3960
          && !switch_val_type->interface_type()->implements_interface(type,
3961
                                                                      &reason))
3962
        {
3963
          if (reason.empty())
3964
            error_at(this->location_, "impossible type switch case");
3965
          else
3966
            error_at(this->location_, "impossible type switch case (%s)",
3967
                     reason.c_str());
3968
        }
3969
 
3970
      Expression* ref = Expression::make_temporary_reference(descriptor_temp,
3971
                                                             loc);
3972
 
3973
      Expression* cond;
3974
      // The language permits case nil, which is of course a constant
3975
      // rather than a type.  It will appear here as an invalid
3976
      // forwarding type.
3977
      if (type->is_nil_constant_as_type())
3978
        cond = Expression::make_binary(OPERATOR_EQEQ, ref,
3979
                                       Expression::make_nil(loc),
3980
                                       loc);
3981
      else
3982
        cond = Runtime::make_call((type->interface_type() == NULL
3983
                                   ? Runtime::IFACETYPEEQ
3984
                                   : Runtime::IFACEI2TP),
3985
                                  loc, 2,
3986
                                  Expression::make_type_descriptor(type, loc),
3987
                                  ref);
3988
 
3989
      Unnamed_label* dest;
3990
      if (!this->is_fallthrough_)
3991
        {
3992
          // if !COND { goto NEXT_CASE_LABEL }
3993
          next_case_label = new Unnamed_label(Linemap::unknown_location());
3994
          dest = next_case_label;
3995
          cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
3996
        }
3997
      else
3998
        {
3999
          // if COND { goto STMTS_LABEL }
4000
          go_assert(stmts_label != NULL);
4001
          if (*stmts_label == NULL)
4002
            *stmts_label = new Unnamed_label(Linemap::unknown_location());
4003
          dest = *stmts_label;
4004
        }
4005
      Block* then_block = new Block(b, loc);
4006
      Statement* s = Statement::make_goto_unnamed_statement(dest, loc);
4007
      then_block->add_statement(s);
4008
      s = Statement::make_if_statement(cond, then_block, NULL, loc);
4009
      b->add_statement(s);
4010
    }
4011
 
4012
  if (this->statements_ != NULL
4013
      || (!this->is_fallthrough_
4014
          && stmts_label != NULL
4015
          && *stmts_label != NULL))
4016
    {
4017
      go_assert(!this->is_fallthrough_);
4018
      if (stmts_label != NULL && *stmts_label != NULL)
4019
        {
4020
          go_assert(!this->is_default_);
4021
          if (this->statements_ != NULL)
4022
            (*stmts_label)->set_location(this->statements_->start_location());
4023
          Statement* s = Statement::make_unnamed_label_statement(*stmts_label);
4024
          b->add_statement(s);
4025
          *stmts_label = NULL;
4026
        }
4027
      if (this->statements_ != NULL)
4028
        b->add_statement(Statement::make_block_statement(this->statements_,
4029
                                                         loc));
4030
    }
4031
 
4032
  if (this->is_fallthrough_)
4033
    go_assert(next_case_label == NULL);
4034
  else
4035
    {
4036
      Location gloc = (this->statements_ == NULL
4037
                              ? loc
4038
                              : this->statements_->end_location());
4039
      b->add_statement(Statement::make_goto_unnamed_statement(break_label,
4040
                                                              gloc));
4041
      if (next_case_label != NULL)
4042
        {
4043
          Statement* s =
4044
            Statement::make_unnamed_label_statement(next_case_label);
4045
          b->add_statement(s);
4046
        }
4047
    }
4048
}
4049
 
4050
// Dump the AST representation for a type case clause
4051
 
4052
void
4053
Type_case_clauses::Type_case_clause::dump_clause(
4054
    Ast_dump_context* ast_dump_context) const
4055
{
4056
  ast_dump_context->print_indent();
4057
  if (this->is_default_)
4058
    {
4059
      ast_dump_context->ostream() << "default:";
4060
    }
4061
  else
4062
    {
4063
      ast_dump_context->ostream() << "case ";
4064
      ast_dump_context->dump_type(this->type_);
4065
      ast_dump_context->ostream() << ":" ;
4066
    }
4067
  ast_dump_context->dump_block(this->statements_);
4068
  if (this->is_fallthrough_)
4069
    {
4070
      ast_dump_context->print_indent();
4071
      ast_dump_context->ostream() <<  " (fallthrough)" << std::endl;
4072
    }
4073
}
4074
 
4075
// Class Type_case_clauses.
4076
 
4077
// Traversal.
4078
 
4079
int
4080
Type_case_clauses::traverse(Traverse* traverse)
4081
{
4082
  for (Type_clauses::iterator p = this->clauses_.begin();
4083
       p != this->clauses_.end();
4084
       ++p)
4085
    {
4086
      if (p->traverse(traverse) == TRAVERSE_EXIT)
4087
        return TRAVERSE_EXIT;
4088
    }
4089
  return TRAVERSE_CONTINUE;
4090
}
4091
 
4092
// Check for duplicate types.
4093
 
4094
void
4095
Type_case_clauses::check_duplicates() const
4096
{
4097
  typedef Unordered_set_hash(const Type*, Type_hash_identical,
4098
                             Type_identical) Types_seen;
4099
  Types_seen types_seen;
4100
  for (Type_clauses::const_iterator p = this->clauses_.begin();
4101
       p != this->clauses_.end();
4102
       ++p)
4103
    {
4104
      Type* t = p->type();
4105
      if (t == NULL)
4106
        continue;
4107
      if (t->is_nil_constant_as_type())
4108
        t = Type::make_nil_type();
4109
      std::pair<Types_seen::iterator, bool> ins = types_seen.insert(t);
4110
      if (!ins.second)
4111
        error_at(p->location(), "duplicate type in switch");
4112
    }
4113
}
4114
 
4115
// Lower the clauses in a type switch.  Add statements to the block B.
4116
// The type descriptor we are switching on is in DESCRIPTOR_TEMP.
4117
// BREAK_LABEL is the label at the end of the type switch.
4118
 
4119
void
4120
Type_case_clauses::lower(Type* switch_val_type, Block* b,
4121
                         Temporary_statement* descriptor_temp,
4122
                         Unnamed_label* break_label) const
4123
{
4124
  const Type_case_clause* default_case = NULL;
4125
 
4126
  Unnamed_label* stmts_label = NULL;
4127
  for (Type_clauses::const_iterator p = this->clauses_.begin();
4128
       p != this->clauses_.end();
4129
       ++p)
4130
    {
4131
      if (!p->is_default())
4132
        p->lower(switch_val_type, b, descriptor_temp, break_label,
4133
                 &stmts_label);
4134
      else
4135
        {
4136
          // We are generating a series of tests, which means that we
4137
          // need to move the default case to the end.
4138
          default_case = &*p;
4139
        }
4140
    }
4141
  go_assert(stmts_label == NULL);
4142
 
4143
  if (default_case != NULL)
4144
    default_case->lower(switch_val_type, b, descriptor_temp, break_label,
4145
                        NULL);
4146
}
4147
 
4148
// Dump the AST representation for case clauses (from a switch statement)
4149
 
4150
void
4151
Type_case_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
4152
{
4153
  for (Type_clauses::const_iterator p = this->clauses_.begin();
4154
       p != this->clauses_.end();
4155
       ++p)
4156
    p->dump_clause(ast_dump_context);
4157
}
4158
 
4159
// Class Type_switch_statement.
4160
 
4161
// Traversal.
4162
 
4163
int
4164
Type_switch_statement::do_traverse(Traverse* traverse)
4165
{
4166
  if (this->var_ == NULL)
4167
    {
4168
      if (this->traverse_expression(traverse, &this->expr_) == TRAVERSE_EXIT)
4169
        return TRAVERSE_EXIT;
4170
    }
4171
  if (this->clauses_ != NULL)
4172
    return this->clauses_->traverse(traverse);
4173
  return TRAVERSE_CONTINUE;
4174
}
4175
 
4176
// Lower a type switch statement to a series of if statements.  The gc
4177
// compiler is able to generate a table in some cases.  However, that
4178
// does not work for us because we may have type descriptors in
4179
// different shared libraries, so we can't compare them with simple
4180
// equality testing.
4181
 
4182
Statement*
4183
Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
4184
                                Statement_inserter*)
4185
{
4186
  const Location loc = this->location();
4187
 
4188
  if (this->clauses_ != NULL)
4189
    this->clauses_->check_duplicates();
4190
 
4191
  Block* b = new Block(enclosing, loc);
4192
 
4193
  Type* val_type = (this->var_ != NULL
4194
                    ? this->var_->var_value()->type()
4195
                    : this->expr_->type());
4196
 
4197
  // var descriptor_temp DESCRIPTOR_TYPE
4198
  Type* descriptor_type = Type::make_type_descriptor_ptr_type();
4199
  Temporary_statement* descriptor_temp =
4200
    Statement::make_temporary(descriptor_type, NULL, loc);
4201
  b->add_statement(descriptor_temp);
4202
 
4203
  if (val_type->interface_type() == NULL)
4204
    {
4205
      // Doing a type switch on a non-interface type.  Should we issue
4206
      // a warning for this case?
4207
      Expression* lhs = Expression::make_temporary_reference(descriptor_temp,
4208
                                                             loc);
4209
      Expression* rhs;
4210
      if (val_type->is_nil_type())
4211
        rhs = Expression::make_nil(loc);
4212
      else
4213
        {
4214
          if (val_type->is_abstract())
4215
            val_type = val_type->make_non_abstract_type();
4216
          rhs = Expression::make_type_descriptor(val_type, loc);
4217
        }
4218
      Statement* s = Statement::make_assignment(lhs, rhs, loc);
4219
      b->add_statement(s);
4220
    }
4221
  else
4222
    {
4223
      // descriptor_temp = ifacetype(val_temp)
4224
      // FIXME: This should be inlined.
4225
      bool is_empty = val_type->interface_type()->is_empty();
4226
      Expression* ref;
4227
      if (this->var_ == NULL)
4228
        ref = this->expr_;
4229
      else
4230
        ref = Expression::make_var_reference(this->var_, loc);
4231
      Expression* call = Runtime::make_call((is_empty
4232
                                             ? Runtime::EFACETYPE
4233
                                             : Runtime::IFACETYPE),
4234
                                            loc, 1, ref);
4235
      Temporary_reference_expression* lhs =
4236
        Expression::make_temporary_reference(descriptor_temp, loc);
4237
      lhs->set_is_lvalue();
4238
      Statement* s = Statement::make_assignment(lhs, call, loc);
4239
      b->add_statement(s);
4240
    }
4241
 
4242
  if (this->clauses_ != NULL)
4243
    this->clauses_->lower(val_type, b, descriptor_temp, this->break_label());
4244
 
4245
  Statement* s = Statement::make_unnamed_label_statement(this->break_label_);
4246
  b->add_statement(s);
4247
 
4248
  return Statement::make_block_statement(b, loc);
4249
}
4250
 
4251
// Return the break label for this type switch statement, creating it
4252
// if necessary.
4253
 
4254
Unnamed_label*
4255
Type_switch_statement::break_label()
4256
{
4257
  if (this->break_label_ == NULL)
4258
    this->break_label_ = new Unnamed_label(this->location());
4259
  return this->break_label_;
4260
}
4261
 
4262
// Dump the AST representation for a type switch statement
4263
 
4264
void
4265
Type_switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
4266
    const
4267
{
4268
  ast_dump_context->print_indent();
4269
  ast_dump_context->ostream() << "switch " << this->var_->name() << " = ";
4270
  ast_dump_context->dump_expression(this->expr_);
4271
  ast_dump_context->ostream() << " .(type)";
4272
  if (ast_dump_context->dump_subblocks())
4273
    {
4274
      ast_dump_context->ostream() << " {" << std::endl;
4275
      this->clauses_->dump_clauses(ast_dump_context);
4276
      ast_dump_context->ostream() << "}";
4277
    }
4278
  ast_dump_context->ostream() << std::endl;
4279
}
4280
 
4281
// Make a type switch statement.
4282
 
4283
Type_switch_statement*
4284
Statement::make_type_switch_statement(Named_object* var, Expression* expr,
4285
                                      Location location)
4286
{
4287
  return new Type_switch_statement(var, expr, location);
4288
}
4289
 
4290
// Class Send_statement.
4291
 
4292
// Traversal.
4293
 
4294
int
4295
Send_statement::do_traverse(Traverse* traverse)
4296
{
4297
  if (this->traverse_expression(traverse, &this->channel_) == TRAVERSE_EXIT)
4298
    return TRAVERSE_EXIT;
4299
  return this->traverse_expression(traverse, &this->val_);
4300
}
4301
 
4302
// Determine types.
4303
 
4304
void
4305
Send_statement::do_determine_types()
4306
{
4307
  this->channel_->determine_type_no_context();
4308
  Type* type = this->channel_->type();
4309
  Type_context context;
4310
  if (type->channel_type() != NULL)
4311
    context.type = type->channel_type()->element_type();
4312
  this->val_->determine_type(&context);
4313
}
4314
 
4315
// Check types.
4316
 
4317
void
4318
Send_statement::do_check_types(Gogo*)
4319
{
4320
  Type* type = this->channel_->type();
4321
  if (type->is_error())
4322
    {
4323
      this->set_is_error();
4324
      return;
4325
    }
4326
  Channel_type* channel_type = type->channel_type();
4327
  if (channel_type == NULL)
4328
    {
4329
      error_at(this->location(), "left operand of %<<-%> must be channel");
4330
      this->set_is_error();
4331
      return;
4332
    }
4333
  Type* element_type = channel_type->element_type();
4334
  if (!Type::are_assignable(element_type, this->val_->type(), NULL))
4335
    {
4336
      this->report_error(_("incompatible types in send"));
4337
      return;
4338
    }
4339
  if (!channel_type->may_send())
4340
    {
4341
      this->report_error(_("invalid send on receive-only channel"));
4342
      return;
4343
    }
4344
}
4345
 
4346
// Convert a send statement to the backend representation.
4347
 
4348
Bstatement*
4349
Send_statement::do_get_backend(Translate_context* context)
4350
{
4351
  Location loc = this->location();
4352
 
4353
  Channel_type* channel_type = this->channel_->type()->channel_type();
4354
  Type* element_type = channel_type->element_type();
4355
  Expression* val = Expression::make_cast(element_type, this->val_, loc);
4356
 
4357
  bool is_small;
4358
  bool can_take_address;
4359
  switch (element_type->base()->classification())
4360
    {
4361
    case Type::TYPE_BOOLEAN:
4362
    case Type::TYPE_INTEGER:
4363
    case Type::TYPE_FUNCTION:
4364
    case Type::TYPE_POINTER:
4365
    case Type::TYPE_MAP:
4366
    case Type::TYPE_CHANNEL:
4367
      is_small = true;
4368
      can_take_address = false;
4369
      break;
4370
 
4371
    case Type::TYPE_FLOAT:
4372
    case Type::TYPE_COMPLEX:
4373
    case Type::TYPE_STRING:
4374
    case Type::TYPE_INTERFACE:
4375
      is_small = false;
4376
      can_take_address = false;
4377
      break;
4378
 
4379
    case Type::TYPE_STRUCT:
4380
      is_small = false;
4381
      can_take_address = true;
4382
      break;
4383
 
4384
    case Type::TYPE_ARRAY:
4385
      is_small = false;
4386
      can_take_address = !element_type->is_slice_type();
4387
      break;
4388
 
4389
    default:
4390
    case Type::TYPE_ERROR:
4391
    case Type::TYPE_VOID:
4392
    case Type::TYPE_SINK:
4393
    case Type::TYPE_NIL:
4394
    case Type::TYPE_NAMED:
4395
    case Type::TYPE_FORWARD:
4396
      go_assert(saw_errors());
4397
      return context->backend()->error_statement();
4398
    }
4399
 
4400
  // Only try to take the address of a variable.  We have already
4401
  // moved variables to the heap, so this should not cause that to
4402
  // happen unnecessarily.
4403
  if (can_take_address
4404
      && val->var_expression() == NULL
4405
      && val->temporary_reference_expression() == NULL)
4406
    can_take_address = false;
4407
 
4408
  Expression* td = Expression::make_type_descriptor(this->channel_->type(),
4409
                                                    loc);
4410
 
4411
  Runtime::Function code;
4412
  Bstatement* btemp = NULL;
4413
  if (is_small)
4414
      {
4415
        // Type is small enough to handle as uint64.
4416
        code = Runtime::SEND_SMALL;
4417
        val = Expression::make_unsafe_cast(Type::lookup_integer_type("uint64"),
4418
                                           val, loc);
4419
      }
4420
  else if (can_take_address)
4421
    {
4422
      // Must pass address of value.  The function doesn't change the
4423
      // value, so just take its address directly.
4424
      code = Runtime::SEND_BIG;
4425
      val = Expression::make_unary(OPERATOR_AND, val, loc);
4426
    }
4427
  else
4428
    {
4429
      // Must pass address of value, but the value is small enough
4430
      // that it might be in registers.  Copy value into temporary
4431
      // variable to take address.
4432
      code = Runtime::SEND_BIG;
4433
      Temporary_statement* temp = Statement::make_temporary(element_type,
4434
                                                            val, loc);
4435
      Expression* ref = Expression::make_temporary_reference(temp, loc);
4436
      val = Expression::make_unary(OPERATOR_AND, ref, loc);
4437
      btemp = temp->get_backend(context);
4438
    }
4439
 
4440
  Expression* call = Runtime::make_call(code, loc, 3, td, this->channel_, val);
4441
 
4442
  context->gogo()->lower_expression(context->function(), NULL, &call);
4443
  Bexpression* bcall = tree_to_expr(call->get_tree(context));
4444
  Bstatement* s = context->backend()->expression_statement(bcall);
4445
 
4446
  if (btemp == NULL)
4447
    return s;
4448
  else
4449
    return context->backend()->compound_statement(btemp, s);
4450
}
4451
 
4452
// Dump the AST representation for a send statement
4453
 
4454
void
4455
Send_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
4456
{
4457
  ast_dump_context->print_indent();
4458
  ast_dump_context->dump_expression(this->channel_);
4459
  ast_dump_context->ostream() << " <- ";
4460
  ast_dump_context->dump_expression(this->val_);
4461
  ast_dump_context->ostream() << std::endl;
4462
}
4463
 
4464
// Make a send statement.
4465
 
4466
Send_statement*
4467
Statement::make_send_statement(Expression* channel, Expression* val,
4468
                               Location location)
4469
{
4470
  return new Send_statement(channel, val, location);
4471
}
4472
 
4473
// Class Select_clauses::Select_clause.
4474
 
4475
// Traversal.
4476
 
4477
int
4478
Select_clauses::Select_clause::traverse(Traverse* traverse)
4479
{
4480
  if (!this->is_lowered_
4481
      && (traverse->traverse_mask()
4482
          & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
4483
    {
4484
      if (this->channel_ != NULL)
4485
        {
4486
          if (Expression::traverse(&this->channel_, traverse) == TRAVERSE_EXIT)
4487
            return TRAVERSE_EXIT;
4488
        }
4489
      if (this->val_ != NULL)
4490
        {
4491
          if (Expression::traverse(&this->val_, traverse) == TRAVERSE_EXIT)
4492
            return TRAVERSE_EXIT;
4493
        }
4494
      if (this->closed_ != NULL)
4495
        {
4496
          if (Expression::traverse(&this->closed_, traverse) == TRAVERSE_EXIT)
4497
            return TRAVERSE_EXIT;
4498
        }
4499
    }
4500
  if (this->statements_ != NULL)
4501
    {
4502
      if (this->statements_->traverse(traverse) == TRAVERSE_EXIT)
4503
        return TRAVERSE_EXIT;
4504
    }
4505
  return TRAVERSE_CONTINUE;
4506
}
4507
 
4508
// Lowering.  We call a function to register this clause, and arrange
4509
// to set any variables in any receive clause.
4510
 
4511
void
4512
Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
4513
                                     Block* b, Temporary_statement* sel)
4514
{
4515
  Location loc = this->location_;
4516
 
4517
  Expression* selref = Expression::make_temporary_reference(sel, loc);
4518
 
4519
  mpz_t ival;
4520
  mpz_init_set_ui(ival, this->index_);
4521
  Expression* index_expr = Expression::make_integer(&ival, NULL, loc);
4522
  mpz_clear(ival);
4523
 
4524
  if (this->is_default_)
4525
    {
4526
      go_assert(this->channel_ == NULL && this->val_ == NULL);
4527
      this->lower_default(b, selref, index_expr);
4528
      this->is_lowered_ = true;
4529
      return;
4530
    }
4531
 
4532
  // Evaluate the channel before the select statement.
4533
  Temporary_statement* channel_temp = Statement::make_temporary(NULL,
4534
                                                                this->channel_,
4535
                                                                loc);
4536
  b->add_statement(channel_temp);
4537
  Expression* chanref = Expression::make_temporary_reference(channel_temp,
4538
                                                             loc);
4539
 
4540
  if (this->is_send_)
4541
    this->lower_send(b, selref, chanref, index_expr);
4542
  else
4543
    this->lower_recv(gogo, function, b, selref, chanref, index_expr);
4544
 
4545
  // Now all references should be handled through the statements, not
4546
  // through here.
4547
  this->is_lowered_ = true;
4548
  this->val_ = NULL;
4549
  this->var_ = NULL;
4550
}
4551
 
4552
// Lower a default clause in a select statement.
4553
 
4554
void
4555
Select_clauses::Select_clause::lower_default(Block* b, Expression* selref,
4556
                                             Expression* index_expr)
4557
{
4558
  Location loc = this->location_;
4559
  Expression* call = Runtime::make_call(Runtime::SELECTDEFAULT, loc, 2, selref,
4560
                                        index_expr);
4561
  b->add_statement(Statement::make_statement(call, true));
4562
}
4563
 
4564
// Lower a send clause in a select statement.
4565
 
4566
void
4567
Select_clauses::Select_clause::lower_send(Block* b, Expression* selref,
4568
                                          Expression* chanref,
4569
                                          Expression* index_expr)
4570
{
4571
  Location loc = this->location_;
4572
 
4573
  Channel_type* ct = this->channel_->type()->channel_type();
4574
  if (ct == NULL)
4575
    return;
4576
 
4577
  Type* valtype = ct->element_type();
4578
 
4579
  // Note that copying the value to a temporary here means that we
4580
  // evaluate the send values in the required order.
4581
  Temporary_statement* val = Statement::make_temporary(valtype, this->val_,
4582
                                                       loc);
4583
  b->add_statement(val);
4584
 
4585
  Expression* valref = Expression::make_temporary_reference(val, loc);
4586
  Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc);
4587
 
4588
  Expression* call = Runtime::make_call(Runtime::SELECTSEND, loc, 4, selref,
4589
                                        chanref, valaddr, index_expr);
4590
  b->add_statement(Statement::make_statement(call, true));
4591
}
4592
 
4593
// Lower a receive clause in a select statement.
4594
 
4595
void
4596
Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
4597
                                          Block* b, Expression* selref,
4598
                                          Expression* chanref,
4599
                                          Expression* index_expr)
4600
{
4601
  Location loc = this->location_;
4602
 
4603
  Channel_type* ct = this->channel_->type()->channel_type();
4604
  if (ct == NULL)
4605
    return;
4606
 
4607
  Type* valtype = ct->element_type();
4608
  Temporary_statement* val = Statement::make_temporary(valtype, NULL, loc);
4609
  b->add_statement(val);
4610
 
4611
  Expression* valref = Expression::make_temporary_reference(val, loc);
4612
  Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc);
4613
 
4614
  Temporary_statement* closed_temp = NULL;
4615
 
4616
  Expression* call;
4617
  if (this->closed_ == NULL && this->closedvar_ == NULL)
4618
    call = Runtime::make_call(Runtime::SELECTRECV, loc, 4, selref, chanref,
4619
                              valaddr, index_expr);
4620
  else
4621
    {
4622
      closed_temp = Statement::make_temporary(Type::lookup_bool_type(), NULL,
4623
                                              loc);
4624
      b->add_statement(closed_temp);
4625
      Expression* cref = Expression::make_temporary_reference(closed_temp,
4626
                                                              loc);
4627
      Expression* caddr = Expression::make_unary(OPERATOR_AND, cref, loc);
4628
      call = Runtime::make_call(Runtime::SELECTRECV2, loc, 5, selref, chanref,
4629
                                valaddr, caddr, index_expr);
4630
    }
4631
 
4632
  b->add_statement(Statement::make_statement(call, true));
4633
 
4634
  // If the block of statements is executed, arrange for the received
4635
  // value to move from VAL to the place where the statements expect
4636
  // it.
4637
 
4638
  Block* init = NULL;
4639
 
4640
  if (this->var_ != NULL)
4641
    {
4642
      go_assert(this->val_ == NULL);
4643
      valref = Expression::make_temporary_reference(val, loc);
4644
      this->var_->var_value()->set_init(valref);
4645
      this->var_->var_value()->clear_type_from_chan_element();
4646
    }
4647
  else if (this->val_ != NULL && !this->val_->is_sink_expression())
4648
    {
4649
      init = new Block(b, loc);
4650
      valref = Expression::make_temporary_reference(val, loc);
4651
      init->add_statement(Statement::make_assignment(this->val_, valref, loc));
4652
    }
4653
 
4654
  if (this->closedvar_ != NULL)
4655
    {
4656
      go_assert(this->closed_ == NULL);
4657
      Expression* cref = Expression::make_temporary_reference(closed_temp,
4658
                                                              loc);
4659
      this->closedvar_->var_value()->set_init(cref);
4660
    }
4661
  else if (this->closed_ != NULL && !this->closed_->is_sink_expression())
4662
    {
4663
      if (init == NULL)
4664
        init = new Block(b, loc);
4665
      Expression* cref = Expression::make_temporary_reference(closed_temp,
4666
                                                              loc);
4667
      init->add_statement(Statement::make_assignment(this->closed_, cref,
4668
                                                     loc));
4669
    }
4670
 
4671
  if (init != NULL)
4672
    {
4673
      gogo->lower_block(function, init);
4674
 
4675
      if (this->statements_ != NULL)
4676
        init->add_statement(Statement::make_block_statement(this->statements_,
4677
                                                            loc));
4678
      this->statements_ = init;
4679
    }
4680
}
4681
 
4682
// Determine types.
4683
 
4684
void
4685
Select_clauses::Select_clause::determine_types()
4686
{
4687
  go_assert(this->is_lowered_);
4688
  if (this->statements_ != NULL)
4689
    this->statements_->determine_types();
4690
}
4691
 
4692
// Check types.
4693
 
4694
void
4695
Select_clauses::Select_clause::check_types()
4696
{
4697
  if (this->is_default_)
4698
    return;
4699
 
4700
  Channel_type* ct = this->channel_->type()->channel_type();
4701
  if (ct == NULL)
4702
    {
4703
      error_at(this->channel_->location(), "expected channel");
4704
      return;
4705
    }
4706
 
4707
  if (this->is_send_ && !ct->may_send())
4708
    error_at(this->location(), "invalid send on receive-only channel");
4709
  else if (!this->is_send_ && !ct->may_receive())
4710
    error_at(this->location(), "invalid receive on send-only channel");
4711
}
4712
 
4713
// Whether this clause may fall through to the statement which follows
4714
// the overall select statement.
4715
 
4716
bool
4717
Select_clauses::Select_clause::may_fall_through() const
4718
{
4719
  if (this->statements_ == NULL)
4720
    return true;
4721
  return this->statements_->may_fall_through();
4722
}
4723
 
4724
// Return the backend representation for the statements to execute.
4725
 
4726
Bstatement*
4727
Select_clauses::Select_clause::get_statements_backend(
4728
    Translate_context* context)
4729
{
4730
  if (this->statements_ == NULL)
4731
    return NULL;
4732
  Bblock* bblock = this->statements_->get_backend(context);
4733
  return context->backend()->block_statement(bblock);
4734
}
4735
 
4736
// Dump the AST representation for a select case clause
4737
 
4738
void
4739
Select_clauses::Select_clause::dump_clause(
4740
    Ast_dump_context* ast_dump_context) const
4741
{
4742
  ast_dump_context->print_indent();
4743
  if (this->is_default_)
4744
    {
4745
      ast_dump_context->ostream() << "default:";
4746
    }
4747
  else
4748
    {
4749
      ast_dump_context->ostream() << "case "  ;
4750
      if (this->is_send_)
4751
        {
4752
          ast_dump_context->dump_expression(this->channel_);
4753
          ast_dump_context->ostream() << " <- " ;
4754
          if (this->val_ != NULL)
4755
            ast_dump_context->dump_expression(this->val_);
4756
        }
4757
      else
4758
        {
4759
          if (this->val_ != NULL)
4760
            ast_dump_context->dump_expression(this->val_);
4761
          if (this->closed_ != NULL)
4762
            {
4763
              // FIXME: can val_ == NULL and closed_ ! = NULL?
4764
              ast_dump_context->ostream() << " , " ;
4765
              ast_dump_context->dump_expression(this->closed_);
4766
            }
4767
          if (this->closedvar_ != NULL || this->var_ != NULL)
4768
            ast_dump_context->ostream() << " := " ;
4769
 
4770
          ast_dump_context->ostream() << " <- " ;
4771
          ast_dump_context->dump_expression(this->channel_);
4772
        }
4773
      ast_dump_context->ostream() << ":" ;
4774
    }
4775
  ast_dump_context->dump_block(this->statements_);
4776
}
4777
 
4778
// Class Select_clauses.
4779
 
4780
// Traversal.
4781
 
4782
int
4783
Select_clauses::traverse(Traverse* traverse)
4784
{
4785
  for (Clauses::iterator p = this->clauses_.begin();
4786
       p != this->clauses_.end();
4787
       ++p)
4788
    {
4789
      if (p->traverse(traverse) == TRAVERSE_EXIT)
4790
        return TRAVERSE_EXIT;
4791
    }
4792
  return TRAVERSE_CONTINUE;
4793
}
4794
 
4795
// Lowering.  Here we pull out the channel and the send values, to
4796
// enforce the order of evaluation.  We also add explicit send and
4797
// receive statements to the clauses.
4798
 
4799
void
4800
Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b,
4801
                      Temporary_statement* sel)
4802
{
4803
  for (Clauses::iterator p = this->clauses_.begin();
4804
       p != this->clauses_.end();
4805
       ++p)
4806
    p->lower(gogo, function, b, sel);
4807
}
4808
 
4809
// Determine types.
4810
 
4811
void
4812
Select_clauses::determine_types()
4813
{
4814
  for (Clauses::iterator p = this->clauses_.begin();
4815
       p != this->clauses_.end();
4816
       ++p)
4817
    p->determine_types();
4818
}
4819
 
4820
// Check types.
4821
 
4822
void
4823
Select_clauses::check_types()
4824
{
4825
  for (Clauses::iterator p = this->clauses_.begin();
4826
       p != this->clauses_.end();
4827
       ++p)
4828
    p->check_types();
4829
}
4830
 
4831
// Return whether these select clauses fall through to the statement
4832
// following the overall select statement.
4833
 
4834
bool
4835
Select_clauses::may_fall_through() const
4836
{
4837
  for (Clauses::const_iterator p = this->clauses_.begin();
4838
       p != this->clauses_.end();
4839
       ++p)
4840
    if (p->may_fall_through())
4841
      return true;
4842
  return false;
4843
}
4844
 
4845
// Convert to the backend representation.  We have already accumulated
4846
// all the select information.  Now we call selectgo, which will
4847
// return the index of the clause to execute.
4848
 
4849
Bstatement*
4850
Select_clauses::get_backend(Translate_context* context,
4851
                            Temporary_statement* sel,
4852
                            Unnamed_label *break_label,
4853
                            Location location)
4854
{
4855
  size_t count = this->clauses_.size();
4856
  std::vector<std::vector<Bexpression*> > cases(count);
4857
  std::vector<Bstatement*> clauses(count);
4858
 
4859
  int i = 0;
4860
  for (Clauses::iterator p = this->clauses_.begin();
4861
       p != this->clauses_.end();
4862
       ++p, ++i)
4863
    {
4864
      int index = p->index();
4865
      mpz_t ival;
4866
      mpz_init_set_ui(ival, index);
4867
      Expression* index_expr = Expression::make_integer(&ival, NULL, location);
4868
      mpz_clear(ival);
4869
      cases[i].push_back(tree_to_expr(index_expr->get_tree(context)));
4870
 
4871
      Bstatement* s = p->get_statements_backend(context);
4872
      Location gloc = (p->statements() == NULL
4873
                       ? p->location()
4874
                       : p->statements()->end_location());
4875
      Bstatement* g = break_label->get_goto(context, gloc);
4876
 
4877
      if (s == NULL)
4878
        clauses[i] = g;
4879
      else
4880
        clauses[i] = context->backend()->compound_statement(s, g);
4881
    }
4882
 
4883
  Expression* selref = Expression::make_temporary_reference(sel, location);
4884
  Expression* call = Runtime::make_call(Runtime::SELECTGO, location, 1,
4885
                                        selref);
4886
  context->gogo()->lower_expression(context->function(), NULL, &call);
4887
  Bexpression* bcall = tree_to_expr(call->get_tree(context));
4888
 
4889
  if (count == 0)
4890
    return context->backend()->expression_statement(bcall);
4891
 
4892
  std::vector<Bstatement*> statements;
4893
  statements.reserve(2);
4894
 
4895
  Bstatement* switch_stmt = context->backend()->switch_statement(bcall,
4896
                                                                 cases,
4897
                                                                 clauses,
4898
                                                                 location);
4899
  statements.push_back(switch_stmt);
4900
 
4901
  Bstatement* ldef = break_label->get_definition(context);
4902
  statements.push_back(ldef);
4903
 
4904
  return context->backend()->statement_list(statements);
4905
}
4906
// Dump the AST representation for select clauses.
4907
 
4908
void
4909
Select_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
4910
{
4911
  for (Clauses::const_iterator p = this->clauses_.begin();
4912
       p != this->clauses_.end();
4913
       ++p)
4914
    p->dump_clause(ast_dump_context);
4915
}
4916
 
4917
// Class Select_statement.
4918
 
4919
// Return the break label for this switch statement, creating it if
4920
// necessary.
4921
 
4922
Unnamed_label*
4923
Select_statement::break_label()
4924
{
4925
  if (this->break_label_ == NULL)
4926
    this->break_label_ = new Unnamed_label(this->location());
4927
  return this->break_label_;
4928
}
4929
 
4930
// Lower a select statement.  This will still return a select
4931
// statement, but it will be modified to implement the order of
4932
// evaluation rules, and to include the send and receive statements as
4933
// explicit statements in the clauses.
4934
 
4935
Statement*
4936
Select_statement::do_lower(Gogo* gogo, Named_object* function,
4937
                           Block* enclosing, Statement_inserter*)
4938
{
4939
  if (this->is_lowered_)
4940
    return this;
4941
 
4942
  Location loc = this->location();
4943
 
4944
  Block* b = new Block(enclosing, loc);
4945
 
4946
  go_assert(this->sel_ == NULL);
4947
 
4948
  mpz_t ival;
4949
  mpz_init_set_ui(ival, this->clauses_->size());
4950
  Expression* size_expr = Expression::make_integer(&ival, NULL, loc);
4951
  mpz_clear(ival);
4952
 
4953
  Expression* call = Runtime::make_call(Runtime::NEWSELECT, loc, 1, size_expr);
4954
 
4955
  this->sel_ = Statement::make_temporary(NULL, call, loc);
4956
  b->add_statement(this->sel_);
4957
 
4958
  this->clauses_->lower(gogo, function, b, this->sel_);
4959
  this->is_lowered_ = true;
4960
  b->add_statement(this);
4961
 
4962
  return Statement::make_block_statement(b, loc);
4963
}
4964
 
4965
// Return the backend representation for a select statement.
4966
 
4967
Bstatement*
4968
Select_statement::do_get_backend(Translate_context* context)
4969
{
4970
  return this->clauses_->get_backend(context, this->sel_, this->break_label(),
4971
                                     this->location());
4972
}
4973
 
4974
// Dump the AST representation for a select statement.
4975
 
4976
void
4977
Select_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
4978
{
4979
  ast_dump_context->print_indent();
4980
  ast_dump_context->ostream() << "select";
4981
  if (ast_dump_context->dump_subblocks())
4982
    {
4983
      ast_dump_context->ostream() << " {" << std::endl;
4984
      this->clauses_->dump_clauses(ast_dump_context);
4985
      ast_dump_context->ostream() << "}";
4986
    }
4987
  ast_dump_context->ostream() << std::endl;
4988
}
4989
 
4990
// Make a select statement.
4991
 
4992
Select_statement*
4993
Statement::make_select_statement(Location location)
4994
{
4995
  return new Select_statement(location);
4996
}
4997
 
4998
// Class For_statement.
4999
 
5000
// Traversal.
5001
 
5002
int
5003
For_statement::do_traverse(Traverse* traverse)
5004
{
5005
  if (this->init_ != NULL)
5006
    {
5007
      if (this->init_->traverse(traverse) == TRAVERSE_EXIT)
5008
        return TRAVERSE_EXIT;
5009
    }
5010
  if (this->cond_ != NULL)
5011
    {
5012
      if (this->traverse_expression(traverse, &this->cond_) == TRAVERSE_EXIT)
5013
        return TRAVERSE_EXIT;
5014
    }
5015
  if (this->post_ != NULL)
5016
    {
5017
      if (this->post_->traverse(traverse) == TRAVERSE_EXIT)
5018
        return TRAVERSE_EXIT;
5019
    }
5020
  return this->statements_->traverse(traverse);
5021
}
5022
 
5023
// Lower a For_statement into if statements and gotos.  Getting rid of
5024
// complex statements make it easier to handle garbage collection.
5025
 
5026
Statement*
5027
For_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
5028
                        Statement_inserter*)
5029
{
5030
  Statement* s;
5031
  Location loc = this->location();
5032
 
5033
  Block* b = new Block(enclosing, this->location());
5034
  if (this->init_ != NULL)
5035
    {
5036
      s = Statement::make_block_statement(this->init_,
5037
                                          this->init_->start_location());
5038
      b->add_statement(s);
5039
    }
5040
 
5041
  Unnamed_label* entry = NULL;
5042
  if (this->cond_ != NULL)
5043
    {
5044
      entry = new Unnamed_label(this->location());
5045
      b->add_statement(Statement::make_goto_unnamed_statement(entry, loc));
5046
    }
5047
 
5048
  Unnamed_label* top = new Unnamed_label(this->location());
5049
  b->add_statement(Statement::make_unnamed_label_statement(top));
5050
 
5051
  s = Statement::make_block_statement(this->statements_,
5052
                                      this->statements_->start_location());
5053
  b->add_statement(s);
5054
 
5055
  Location end_loc = this->statements_->end_location();
5056
 
5057
  Unnamed_label* cont = this->continue_label_;
5058
  if (cont != NULL)
5059
    b->add_statement(Statement::make_unnamed_label_statement(cont));
5060
 
5061
  if (this->post_ != NULL)
5062
    {
5063
      s = Statement::make_block_statement(this->post_,
5064
                                          this->post_->start_location());
5065
      b->add_statement(s);
5066
      end_loc = this->post_->end_location();
5067
    }
5068
 
5069
  if (this->cond_ == NULL)
5070
    b->add_statement(Statement::make_goto_unnamed_statement(top, end_loc));
5071
  else
5072
    {
5073
      b->add_statement(Statement::make_unnamed_label_statement(entry));
5074
 
5075
      Location cond_loc = this->cond_->location();
5076
      Block* then_block = new Block(b, cond_loc);
5077
      s = Statement::make_goto_unnamed_statement(top, cond_loc);
5078
      then_block->add_statement(s);
5079
 
5080
      s = Statement::make_if_statement(this->cond_, then_block, NULL, cond_loc);
5081
      b->add_statement(s);
5082
    }
5083
 
5084
  Unnamed_label* brk = this->break_label_;
5085
  if (brk != NULL)
5086
    b->add_statement(Statement::make_unnamed_label_statement(brk));
5087
 
5088
  b->set_end_location(end_loc);
5089
 
5090
  return Statement::make_block_statement(b, loc);
5091
}
5092
 
5093
// Return the break label, creating it if necessary.
5094
 
5095
Unnamed_label*
5096
For_statement::break_label()
5097
{
5098
  if (this->break_label_ == NULL)
5099
    this->break_label_ = new Unnamed_label(this->location());
5100
  return this->break_label_;
5101
}
5102
 
5103
// Return the continue LABEL_EXPR.
5104
 
5105
Unnamed_label*
5106
For_statement::continue_label()
5107
{
5108
  if (this->continue_label_ == NULL)
5109
    this->continue_label_ = new Unnamed_label(this->location());
5110
  return this->continue_label_;
5111
}
5112
 
5113
// Set the break and continue labels a for statement.  This is used
5114
// when lowering a for range statement.
5115
 
5116
void
5117
For_statement::set_break_continue_labels(Unnamed_label* break_label,
5118
                                         Unnamed_label* continue_label)
5119
{
5120
  go_assert(this->break_label_ == NULL && this->continue_label_ == NULL);
5121
  this->break_label_ = break_label;
5122
  this->continue_label_ = continue_label;
5123
}
5124
 
5125
// Dump the AST representation for a for statement.
5126
 
5127
void
5128
For_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
5129
{
5130
  if (this->init_ != NULL && ast_dump_context->dump_subblocks())
5131
    {
5132
      ast_dump_context->print_indent();
5133
      ast_dump_context->indent();
5134
      ast_dump_context->ostream() << "// INIT  " << std::endl;
5135
      ast_dump_context->dump_block(this->init_);
5136
      ast_dump_context->unindent();
5137
    }
5138
  ast_dump_context->print_indent();
5139
  ast_dump_context->ostream() << "for ";
5140
  if (this->cond_ != NULL)
5141
    ast_dump_context->dump_expression(this->cond_);
5142
 
5143
  if (ast_dump_context->dump_subblocks())
5144
    {
5145
      ast_dump_context->ostream() << " {" << std::endl;
5146
      ast_dump_context->dump_block(this->statements_);
5147
      if (this->init_ != NULL)
5148
        {
5149
          ast_dump_context->print_indent();
5150
          ast_dump_context->ostream() << "// POST " << std::endl;
5151
          ast_dump_context->dump_block(this->post_);
5152
        }
5153
      ast_dump_context->unindent();
5154
 
5155
      ast_dump_context->print_indent();
5156
      ast_dump_context->ostream() << "}";
5157
    }
5158
 
5159
  ast_dump_context->ostream() << std::endl;
5160
}
5161
 
5162
// Make a for statement.
5163
 
5164
For_statement*
5165
Statement::make_for_statement(Block* init, Expression* cond, Block* post,
5166
                              Location location)
5167
{
5168
  return new For_statement(init, cond, post, location);
5169
}
5170
 
5171
// Class For_range_statement.
5172
 
5173
// Traversal.
5174
 
5175
int
5176
For_range_statement::do_traverse(Traverse* traverse)
5177
{
5178
  if (this->traverse_expression(traverse, &this->index_var_) == TRAVERSE_EXIT)
5179
    return TRAVERSE_EXIT;
5180
  if (this->value_var_ != NULL)
5181
    {
5182
      if (this->traverse_expression(traverse, &this->value_var_)
5183
          == TRAVERSE_EXIT)
5184
        return TRAVERSE_EXIT;
5185
    }
5186
  if (this->traverse_expression(traverse, &this->range_) == TRAVERSE_EXIT)
5187
    return TRAVERSE_EXIT;
5188
  return this->statements_->traverse(traverse);
5189
}
5190
 
5191
// Lower a for range statement.  For simplicity we lower this into a
5192
// for statement, which will then be lowered in turn to goto
5193
// statements.
5194
 
5195
Statement*
5196
For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
5197
                              Statement_inserter*)
5198
{
5199
  Type* range_type = this->range_->type();
5200
  if (range_type->points_to() != NULL
5201
      && range_type->points_to()->array_type() != NULL
5202
      && !range_type->points_to()->is_slice_type())
5203
    range_type = range_type->points_to();
5204
 
5205
  Type* index_type;
5206
  Type* value_type = NULL;
5207
  if (range_type->array_type() != NULL)
5208
    {
5209
      index_type = Type::lookup_integer_type("int");
5210
      value_type = range_type->array_type()->element_type();
5211
    }
5212
  else if (range_type->is_string_type())
5213
    {
5214
      index_type = Type::lookup_integer_type("int");
5215
      value_type = Type::lookup_integer_type("int32");
5216
    }
5217
  else if (range_type->map_type() != NULL)
5218
    {
5219
      index_type = range_type->map_type()->key_type();
5220
      value_type = range_type->map_type()->val_type();
5221
    }
5222
  else if (range_type->channel_type() != NULL)
5223
    {
5224
      index_type = range_type->channel_type()->element_type();
5225
      if (this->value_var_ != NULL)
5226
        {
5227
          if (!this->value_var_->type()->is_error())
5228
            this->report_error(_("too many variables for range clause "
5229
                                 "with channel"));
5230
          return Statement::make_error_statement(this->location());
5231
        }
5232
    }
5233
  else
5234
    {
5235
      this->report_error(_("range clause must have "
5236
                           "array, slice, string, map, or channel type"));
5237
      return Statement::make_error_statement(this->location());
5238
    }
5239
 
5240
  Location loc = this->location();
5241
  Block* temp_block = new Block(enclosing, loc);
5242
 
5243
  Named_object* range_object = NULL;
5244
  Temporary_statement* range_temp = NULL;
5245
  Var_expression* ve = this->range_->var_expression();
5246
  if (ve != NULL)
5247
    range_object = ve->named_object();
5248
  else
5249
    {
5250
      range_temp = Statement::make_temporary(NULL, this->range_, loc);
5251
      temp_block->add_statement(range_temp);
5252
      this->range_ = NULL;
5253
    }
5254
 
5255
  Temporary_statement* index_temp = Statement::make_temporary(index_type,
5256
                                                              NULL, loc);
5257
  temp_block->add_statement(index_temp);
5258
 
5259
  Temporary_statement* value_temp = NULL;
5260
  if (this->value_var_ != NULL)
5261
    {
5262
      value_temp = Statement::make_temporary(value_type, NULL, loc);
5263
      temp_block->add_statement(value_temp);
5264
    }
5265
 
5266
  Block* body = new Block(temp_block, loc);
5267
 
5268
  Block* init;
5269
  Expression* cond;
5270
  Block* iter_init;
5271
  Block* post;
5272
 
5273
  // Arrange to do a loop appropriate for the type.  We will produce
5274
  //   for INIT ; COND ; POST {
5275
  //           ITER_INIT
5276
  //           INDEX = INDEX_TEMP
5277
  //           VALUE = VALUE_TEMP // If there is a value
5278
  //           original statements
5279
  //   }
5280
 
5281
  if (range_type->is_slice_type())
5282
    this->lower_range_slice(gogo, temp_block, body, range_object, range_temp,
5283
                            index_temp, value_temp, &init, &cond, &iter_init,
5284
                            &post);
5285
  else if (range_type->array_type() != NULL)
5286
    this->lower_range_array(gogo, temp_block, body, range_object, range_temp,
5287
                            index_temp, value_temp, &init, &cond, &iter_init,
5288
                            &post);
5289
  else if (range_type->is_string_type())
5290
    this->lower_range_string(gogo, temp_block, body, range_object, range_temp,
5291
                             index_temp, value_temp, &init, &cond, &iter_init,
5292
                             &post);
5293
  else if (range_type->map_type() != NULL)
5294
    this->lower_range_map(gogo, temp_block, body, range_object, range_temp,
5295
                          index_temp, value_temp, &init, &cond, &iter_init,
5296
                          &post);
5297
  else if (range_type->channel_type() != NULL)
5298
    this->lower_range_channel(gogo, temp_block, body, range_object, range_temp,
5299
                              index_temp, value_temp, &init, &cond, &iter_init,
5300
                              &post);
5301
  else
5302
    go_unreachable();
5303
 
5304
  if (iter_init != NULL)
5305
    body->add_statement(Statement::make_block_statement(iter_init, loc));
5306
 
5307
  Statement* assign;
5308
  Expression* index_ref = Expression::make_temporary_reference(index_temp, loc);
5309
  if (this->value_var_ == NULL)
5310
    {
5311
      assign = Statement::make_assignment(this->index_var_, index_ref, loc);
5312
    }
5313
  else
5314
    {
5315
      Expression_list* lhs = new Expression_list();
5316
      lhs->push_back(this->index_var_);
5317
      lhs->push_back(this->value_var_);
5318
 
5319
      Expression_list* rhs = new Expression_list();
5320
      rhs->push_back(index_ref);
5321
      rhs->push_back(Expression::make_temporary_reference(value_temp, loc));
5322
 
5323
      assign = Statement::make_tuple_assignment(lhs, rhs, loc);
5324
    }
5325
  body->add_statement(assign);
5326
 
5327
  body->add_statement(Statement::make_block_statement(this->statements_, loc));
5328
 
5329
  body->set_end_location(this->statements_->end_location());
5330
 
5331
  For_statement* loop = Statement::make_for_statement(init, cond, post,
5332
                                                      this->location());
5333
  loop->add_statements(body);
5334
  loop->set_break_continue_labels(this->break_label_, this->continue_label_);
5335
 
5336
  temp_block->add_statement(loop);
5337
 
5338
  return Statement::make_block_statement(temp_block, loc);
5339
}
5340
 
5341
// Return a reference to the range, which may be in RANGE_OBJECT or in
5342
// RANGE_TEMP.
5343
 
5344
Expression*
5345
For_range_statement::make_range_ref(Named_object* range_object,
5346
                                    Temporary_statement* range_temp,
5347
                                    Location loc)
5348
{
5349
  if (range_object != NULL)
5350
    return Expression::make_var_reference(range_object, loc);
5351
  else
5352
    return Expression::make_temporary_reference(range_temp, loc);
5353
}
5354
 
5355
// Return a call to the predeclared function FUNCNAME passing a
5356
// reference to the temporary variable ARG.
5357
 
5358
Expression*
5359
For_range_statement::call_builtin(Gogo* gogo, const char* funcname,
5360
                                  Expression* arg,
5361
                                  Location loc)
5362
{
5363
  Named_object* no = gogo->lookup_global(funcname);
5364
  go_assert(no != NULL && no->is_function_declaration());
5365
  Expression* func = Expression::make_func_reference(no, NULL, loc);
5366
  Expression_list* params = new Expression_list();
5367
  params->push_back(arg);
5368
  return Expression::make_call(func, params, false, loc);
5369
}
5370
 
5371
// Lower a for range over an array.
5372
 
5373
void
5374
For_range_statement::lower_range_array(Gogo* gogo,
5375
                                       Block* enclosing,
5376
                                       Block* body_block,
5377
                                       Named_object* range_object,
5378
                                       Temporary_statement* range_temp,
5379
                                       Temporary_statement* index_temp,
5380
                                       Temporary_statement* value_temp,
5381
                                       Block** pinit,
5382
                                       Expression** pcond,
5383
                                       Block** piter_init,
5384
                                       Block** ppost)
5385
{
5386
  Location loc = this->location();
5387
 
5388
  // The loop we generate:
5389
  //   len_temp := len(range)
5390
  //   for index_temp = 0; index_temp < len_temp; index_temp++ {
5391
  //           value_temp = range[index_temp]
5392
  //           index = index_temp
5393
  //           value = value_temp
5394
  //           original body
5395
  //   }
5396
 
5397
  // Set *PINIT to
5398
  //   var len_temp int
5399
  //   len_temp = len(range)
5400
  //   index_temp = 0
5401
 
5402
  Block* init = new Block(enclosing, loc);
5403
 
5404
  Expression* ref = this->make_range_ref(range_object, range_temp, loc);
5405
  Expression* len_call = this->call_builtin(gogo, "len", ref, loc);
5406
  Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
5407
                                                            len_call, loc);
5408
  init->add_statement(len_temp);
5409
 
5410
  mpz_t zval;
5411
  mpz_init_set_ui(zval, 0UL);
5412
  Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
5413
  mpz_clear(zval);
5414
 
5415
  Temporary_reference_expression* tref =
5416
    Expression::make_temporary_reference(index_temp, loc);
5417
  tref->set_is_lvalue();
5418
  Statement* s = Statement::make_assignment(tref, zexpr, loc);
5419
  init->add_statement(s);
5420
 
5421
  *pinit = init;
5422
 
5423
  // Set *PCOND to
5424
  //   index_temp < len_temp
5425
 
5426
  ref = Expression::make_temporary_reference(index_temp, loc);
5427
  Expression* ref2 = Expression::make_temporary_reference(len_temp, loc);
5428
  Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc);
5429
 
5430
  *pcond = lt;
5431
 
5432
  // Set *PITER_INIT to
5433
  //   value_temp = range[index_temp]
5434
 
5435
  Block* iter_init = NULL;
5436
  if (value_temp != NULL)
5437
    {
5438
      iter_init = new Block(body_block, loc);
5439
 
5440
      ref = this->make_range_ref(range_object, range_temp, loc);
5441
      Expression* ref2 = Expression::make_temporary_reference(index_temp, loc);
5442
      Expression* index = Expression::make_index(ref, ref2, NULL, loc);
5443
 
5444
      tref = Expression::make_temporary_reference(value_temp, loc);
5445
      tref->set_is_lvalue();
5446
      s = Statement::make_assignment(tref, index, loc);
5447
 
5448
      iter_init->add_statement(s);
5449
    }
5450
  *piter_init = iter_init;
5451
 
5452
  // Set *PPOST to
5453
  //   index_temp++
5454
 
5455
  Block* post = new Block(enclosing, loc);
5456
  tref = Expression::make_temporary_reference(index_temp, loc);
5457
  tref->set_is_lvalue();
5458
  s = Statement::make_inc_statement(tref);
5459
  post->add_statement(s);
5460
  *ppost = post;
5461
}
5462
 
5463
// Lower a for range over a slice.
5464
 
5465
void
5466
For_range_statement::lower_range_slice(Gogo* gogo,
5467
                                       Block* enclosing,
5468
                                       Block* body_block,
5469
                                       Named_object* range_object,
5470
                                       Temporary_statement* range_temp,
5471
                                       Temporary_statement* index_temp,
5472
                                       Temporary_statement* value_temp,
5473
                                       Block** pinit,
5474
                                       Expression** pcond,
5475
                                       Block** piter_init,
5476
                                       Block** ppost)
5477
{
5478
  Location loc = this->location();
5479
 
5480
  // The loop we generate:
5481
  //   for_temp := range
5482
  //   len_temp := len(for_temp)
5483
  //   for index_temp = 0; index_temp < len_temp; index_temp++ {
5484
  //           value_temp = for_temp[index_temp]
5485
  //           index = index_temp
5486
  //           value = value_temp
5487
  //           original body
5488
  //   }
5489
  //
5490
  // Using for_temp means that we don't need to check bounds when
5491
  // fetching range_temp[index_temp].
5492
 
5493
  // Set *PINIT to
5494
  //   range_temp := range
5495
  //   var len_temp int
5496
  //   len_temp = len(range_temp)
5497
  //   index_temp = 0
5498
 
5499
  Block* init = new Block(enclosing, loc);
5500
 
5501
  Expression* ref = this->make_range_ref(range_object, range_temp, loc);
5502
  Temporary_statement* for_temp = Statement::make_temporary(NULL, ref, loc);
5503
  init->add_statement(for_temp);
5504
 
5505
  ref = Expression::make_temporary_reference(for_temp, loc);
5506
  Expression* len_call = this->call_builtin(gogo, "len", ref, loc);
5507
  Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
5508
                                                            len_call, loc);
5509
  init->add_statement(len_temp);
5510
 
5511
  mpz_t zval;
5512
  mpz_init_set_ui(zval, 0UL);
5513
  Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
5514
  mpz_clear(zval);
5515
 
5516
  Temporary_reference_expression* tref =
5517
    Expression::make_temporary_reference(index_temp, loc);
5518
  tref->set_is_lvalue();
5519
  Statement* s = Statement::make_assignment(tref, zexpr, loc);
5520
  init->add_statement(s);
5521
 
5522
  *pinit = init;
5523
 
5524
  // Set *PCOND to
5525
  //   index_temp < len_temp
5526
 
5527
  ref = Expression::make_temporary_reference(index_temp, loc);
5528
  Expression* ref2 = Expression::make_temporary_reference(len_temp, loc);
5529
  Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc);
5530
 
5531
  *pcond = lt;
5532
 
5533
  // Set *PITER_INIT to
5534
  //   value_temp = range[index_temp]
5535
 
5536
  Block* iter_init = NULL;
5537
  if (value_temp != NULL)
5538
    {
5539
      iter_init = new Block(body_block, loc);
5540
 
5541
      ref = Expression::make_temporary_reference(for_temp, loc);
5542
      Expression* ref2 = Expression::make_temporary_reference(index_temp, loc);
5543
      Expression* index = Expression::make_index(ref, ref2, NULL, loc);
5544
 
5545
      tref = Expression::make_temporary_reference(value_temp, loc);
5546
      tref->set_is_lvalue();
5547
      s = Statement::make_assignment(tref, index, loc);
5548
 
5549
      iter_init->add_statement(s);
5550
    }
5551
  *piter_init = iter_init;
5552
 
5553
  // Set *PPOST to
5554
  //   index_temp++
5555
 
5556
  Block* post = new Block(enclosing, loc);
5557
  tref = Expression::make_temporary_reference(index_temp, loc);
5558
  tref->set_is_lvalue();
5559
  s = Statement::make_inc_statement(tref);
5560
  post->add_statement(s);
5561
  *ppost = post;
5562
}
5563
 
5564
// Lower a for range over a string.
5565
 
5566
void
5567
For_range_statement::lower_range_string(Gogo*,
5568
                                        Block* enclosing,
5569
                                        Block* body_block,
5570
                                        Named_object* range_object,
5571
                                        Temporary_statement* range_temp,
5572
                                        Temporary_statement* index_temp,
5573
                                        Temporary_statement* value_temp,
5574
                                        Block** pinit,
5575
                                        Expression** pcond,
5576
                                        Block** piter_init,
5577
                                        Block** ppost)
5578
{
5579
  Location loc = this->location();
5580
 
5581
  // The loop we generate:
5582
  //   var next_index_temp int
5583
  //   for index_temp = 0; ; index_temp = next_index_temp {
5584
  //           next_index_temp, value_temp = stringiter2(range, index_temp)
5585
  //           if next_index_temp == 0 {
5586
  //                   break
5587
  //           }
5588
  //           index = index_temp
5589
  //           value = value_temp
5590
  //           original body
5591
  //   }
5592
 
5593
  // Set *PINIT to
5594
  //   var next_index_temp int
5595
  //   index_temp = 0
5596
 
5597
  Block* init = new Block(enclosing, loc);
5598
 
5599
  Temporary_statement* next_index_temp =
5600
    Statement::make_temporary(index_temp->type(), NULL, loc);
5601
  init->add_statement(next_index_temp);
5602
 
5603
  mpz_t zval;
5604
  mpz_init_set_ui(zval, 0UL);
5605
  Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
5606
 
5607
  Temporary_reference_expression* ref =
5608
    Expression::make_temporary_reference(index_temp, loc);
5609
  ref->set_is_lvalue();
5610
  Statement* s = Statement::make_assignment(ref, zexpr, loc);
5611
 
5612
  init->add_statement(s);
5613
  *pinit = init;
5614
 
5615
  // The loop has no condition.
5616
 
5617
  *pcond = NULL;
5618
 
5619
  // Set *PITER_INIT to
5620
  //   next_index_temp = runtime.stringiter(range, index_temp)
5621
  // or
5622
  //   next_index_temp, value_temp = runtime.stringiter2(range, index_temp)
5623
  // followed by
5624
  //   if next_index_temp == 0 {
5625
  //           break
5626
  //   }
5627
 
5628
  Block* iter_init = new Block(body_block, loc);
5629
 
5630
  Expression* p1 = this->make_range_ref(range_object, range_temp, loc);
5631
  Expression* p2 = Expression::make_temporary_reference(index_temp, loc);
5632
  Call_expression* call = Runtime::make_call((value_temp == NULL
5633
                                              ? Runtime::STRINGITER
5634
                                              : Runtime::STRINGITER2),
5635
                                             loc, 2, p1, p2);
5636
 
5637
  if (value_temp == NULL)
5638
    {
5639
      ref = Expression::make_temporary_reference(next_index_temp, loc);
5640
      ref->set_is_lvalue();
5641
      s = Statement::make_assignment(ref, call, loc);
5642
    }
5643
  else
5644
    {
5645
      Expression_list* lhs = new Expression_list();
5646
 
5647
      ref = Expression::make_temporary_reference(next_index_temp, loc);
5648
      ref->set_is_lvalue();
5649
      lhs->push_back(ref);
5650
 
5651
      ref = Expression::make_temporary_reference(value_temp, loc);
5652
      ref->set_is_lvalue();
5653
      lhs->push_back(ref);
5654
 
5655
      Expression_list* rhs = new Expression_list();
5656
      rhs->push_back(Expression::make_call_result(call, 0));
5657
      rhs->push_back(Expression::make_call_result(call, 1));
5658
 
5659
      s = Statement::make_tuple_assignment(lhs, rhs, loc);
5660
    }
5661
  iter_init->add_statement(s);
5662
 
5663
  ref = Expression::make_temporary_reference(next_index_temp, loc);
5664
  zexpr = Expression::make_integer(&zval, NULL, loc);
5665
  mpz_clear(zval);
5666
  Expression* equals = Expression::make_binary(OPERATOR_EQEQ, ref, zexpr, loc);
5667
 
5668
  Block* then_block = new Block(iter_init, loc);
5669
  s = Statement::make_break_statement(this->break_label(), loc);
5670
  then_block->add_statement(s);
5671
 
5672
  s = Statement::make_if_statement(equals, then_block, NULL, loc);
5673
  iter_init->add_statement(s);
5674
 
5675
  *piter_init = iter_init;
5676
 
5677
  // Set *PPOST to
5678
  //   index_temp = next_index_temp
5679
 
5680
  Block* post = new Block(enclosing, loc);
5681
 
5682
  Temporary_reference_expression* lhs =
5683
    Expression::make_temporary_reference(index_temp, loc);
5684
  lhs->set_is_lvalue();
5685
  Expression* rhs = Expression::make_temporary_reference(next_index_temp, loc);
5686
  s = Statement::make_assignment(lhs, rhs, loc);
5687
 
5688
  post->add_statement(s);
5689
  *ppost = post;
5690
}
5691
 
5692
// Lower a for range over a map.
5693
 
5694
void
5695
For_range_statement::lower_range_map(Gogo*,
5696
                                     Block* enclosing,
5697
                                     Block* body_block,
5698
                                     Named_object* range_object,
5699
                                     Temporary_statement* range_temp,
5700
                                     Temporary_statement* index_temp,
5701
                                     Temporary_statement* value_temp,
5702
                                     Block** pinit,
5703
                                     Expression** pcond,
5704
                                     Block** piter_init,
5705
                                     Block** ppost)
5706
{
5707
  Location loc = this->location();
5708
 
5709
  // The runtime uses a struct to handle ranges over a map.  The
5710
  // struct is four pointers long.  The first pointer is NULL when we
5711
  // have completed the iteration.
5712
 
5713
  // The loop we generate:
5714
  //   var hiter map_iteration_struct
5715
  //   for mapiterinit(range, &hiter); hiter[0] != nil; mapiternext(&hiter) {
5716
  //           mapiter2(hiter, &index_temp, &value_temp)
5717
  //           index = index_temp
5718
  //           value = value_temp
5719
  //           original body
5720
  //   }
5721
 
5722
  // Set *PINIT to
5723
  //   var hiter map_iteration_struct
5724
  //   runtime.mapiterinit(range, &hiter)
5725
 
5726
  Block* init = new Block(enclosing, loc);
5727
 
5728
  Type* map_iteration_type = Runtime::map_iteration_type();
5729
  Temporary_statement* hiter = Statement::make_temporary(map_iteration_type,
5730
                                                         NULL, loc);
5731
  init->add_statement(hiter);
5732
 
5733
  Expression* p1 = this->make_range_ref(range_object, range_temp, loc);
5734
  Expression* ref = Expression::make_temporary_reference(hiter, loc);
5735
  Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
5736
  Expression* call = Runtime::make_call(Runtime::MAPITERINIT, loc, 2, p1, p2);
5737
  init->add_statement(Statement::make_statement(call, true));
5738
 
5739
  *pinit = init;
5740
 
5741
  // Set *PCOND to
5742
  //   hiter[0] != nil
5743
 
5744
  ref = Expression::make_temporary_reference(hiter, loc);
5745
 
5746
  mpz_t zval;
5747
  mpz_init_set_ui(zval, 0UL);
5748
  Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
5749
  mpz_clear(zval);
5750
 
5751
  Expression* index = Expression::make_index(ref, zexpr, NULL, loc);
5752
 
5753
  Expression* ne = Expression::make_binary(OPERATOR_NOTEQ, index,
5754
                                           Expression::make_nil(loc),
5755
                                           loc);
5756
 
5757
  *pcond = ne;
5758
 
5759
  // Set *PITER_INIT to
5760
  //   mapiter1(hiter, &index_temp)
5761
  // or
5762
  //   mapiter2(hiter, &index_temp, &value_temp)
5763
 
5764
  Block* iter_init = new Block(body_block, loc);
5765
 
5766
  ref = Expression::make_temporary_reference(hiter, loc);
5767
  p1 = Expression::make_unary(OPERATOR_AND, ref, loc);
5768
  ref = Expression::make_temporary_reference(index_temp, loc);
5769
  p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
5770
  if (value_temp == NULL)
5771
    call = Runtime::make_call(Runtime::MAPITER1, loc, 2, p1, p2);
5772
  else
5773
    {
5774
      ref = Expression::make_temporary_reference(value_temp, loc);
5775
      Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
5776
      call = Runtime::make_call(Runtime::MAPITER2, loc, 3, p1, p2, p3);
5777
    }
5778
  iter_init->add_statement(Statement::make_statement(call, true));
5779
 
5780
  *piter_init = iter_init;
5781
 
5782
  // Set *PPOST to
5783
  //   mapiternext(&hiter)
5784
 
5785
  Block* post = new Block(enclosing, loc);
5786
 
5787
  ref = Expression::make_temporary_reference(hiter, loc);
5788
  p1 = Expression::make_unary(OPERATOR_AND, ref, loc);
5789
  call = Runtime::make_call(Runtime::MAPITERNEXT, loc, 1, p1);
5790
  post->add_statement(Statement::make_statement(call, true));
5791
 
5792
  *ppost = post;
5793
}
5794
 
5795
// Lower a for range over a channel.
5796
 
5797
void
5798
For_range_statement::lower_range_channel(Gogo*,
5799
                                         Block*,
5800
                                         Block* body_block,
5801
                                         Named_object* range_object,
5802
                                         Temporary_statement* range_temp,
5803
                                         Temporary_statement* index_temp,
5804
                                         Temporary_statement* value_temp,
5805
                                         Block** pinit,
5806
                                         Expression** pcond,
5807
                                         Block** piter_init,
5808
                                         Block** ppost)
5809
{
5810
  go_assert(value_temp == NULL);
5811
 
5812
  Location loc = this->location();
5813
 
5814
  // The loop we generate:
5815
  //   for {
5816
  //           index_temp, ok_temp = <-range
5817
  //           if !ok_temp {
5818
  //                   break
5819
  //           }
5820
  //           index = index_temp
5821
  //           original body
5822
  //   }
5823
 
5824
  // We have no initialization code, no condition, and no post code.
5825
 
5826
  *pinit = NULL;
5827
  *pcond = NULL;
5828
  *ppost = NULL;
5829
 
5830
  // Set *PITER_INIT to
5831
  //   index_temp, ok_temp = <-range
5832
  //   if !ok_temp {
5833
  //           break
5834
  //   }
5835
 
5836
  Block* iter_init = new Block(body_block, loc);
5837
 
5838
  Temporary_statement* ok_temp =
5839
    Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
5840
  iter_init->add_statement(ok_temp);
5841
 
5842
  Expression* cref = this->make_range_ref(range_object, range_temp, loc);
5843
  Temporary_reference_expression* iref =
5844
    Expression::make_temporary_reference(index_temp, loc);
5845
  iref->set_is_lvalue();
5846
  Temporary_reference_expression* oref =
5847
    Expression::make_temporary_reference(ok_temp, loc);
5848
  oref->set_is_lvalue();
5849
  Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref,
5850
                                                          loc);
5851
  iter_init->add_statement(s);
5852
 
5853
  Block* then_block = new Block(iter_init, loc);
5854
  s = Statement::make_break_statement(this->break_label(), loc);
5855
  then_block->add_statement(s);
5856
 
5857
  oref = Expression::make_temporary_reference(ok_temp, loc);
5858
  Expression* cond = Expression::make_unary(OPERATOR_NOT, oref, loc);
5859
  s = Statement::make_if_statement(cond, then_block, NULL, loc);
5860
  iter_init->add_statement(s);
5861
 
5862
  *piter_init = iter_init;
5863
}
5864
 
5865
// Return the break LABEL_EXPR.
5866
 
5867
Unnamed_label*
5868
For_range_statement::break_label()
5869
{
5870
  if (this->break_label_ == NULL)
5871
    this->break_label_ = new Unnamed_label(this->location());
5872
  return this->break_label_;
5873
}
5874
 
5875
// Return the continue LABEL_EXPR.
5876
 
5877
Unnamed_label*
5878
For_range_statement::continue_label()
5879
{
5880
  if (this->continue_label_ == NULL)
5881
    this->continue_label_ = new Unnamed_label(this->location());
5882
  return this->continue_label_;
5883
}
5884
 
5885
// Dump the AST representation for a for range statement.
5886
 
5887
void
5888
For_range_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
5889
{
5890
 
5891
  ast_dump_context->print_indent();
5892
  ast_dump_context->ostream() << "for ";
5893
  ast_dump_context->dump_expression(this->index_var_);
5894
  if (this->value_var_ != NULL)
5895
    {
5896
      ast_dump_context->ostream() << ", ";
5897
      ast_dump_context->dump_expression(this->value_var_);
5898
    }
5899
 
5900
  ast_dump_context->ostream() << " = range ";
5901
  ast_dump_context->dump_expression(this->range_);
5902
  if (ast_dump_context->dump_subblocks())
5903
    {
5904
      ast_dump_context->ostream() << " {" << std::endl;
5905
 
5906
      ast_dump_context->indent();
5907
 
5908
      ast_dump_context->dump_block(this->statements_);
5909
 
5910
      ast_dump_context->unindent();
5911
      ast_dump_context->print_indent();
5912
      ast_dump_context->ostream() << "}";
5913
    }
5914
  ast_dump_context->ostream() << std::endl;
5915
}
5916
 
5917
// Make a for statement with a range clause.
5918
 
5919
For_range_statement*
5920
Statement::make_for_range_statement(Expression* index_var,
5921
                                    Expression* value_var,
5922
                                    Expression* range,
5923
                                    Location location)
5924
{
5925
  return new For_range_statement(index_var, value_var, range, location);
5926
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.