OSDN Git Service

compiler: Give an error if a variable is defined but not used.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 23 Jan 2012 23:55:31 +0000 (23:55 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 23 Jan 2012 23:55:31 +0000 (23:55 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@183458 138bc75d-0d04-0410-961f-82ee72b054a4

22 files changed:
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/lex.cc
gcc/go/gofrontend/lex.h
gcc/go/gofrontend/parse.cc
gcc/go/gofrontend/parse.h
gcc/testsuite/go.test/test/blank1.go
gcc/testsuite/go.test/test/fixedbugs/bug014.go
gcc/testsuite/go.test/test/fixedbugs/bug108.go
gcc/testsuite/go.test/test/fixedbugs/bug141.go
gcc/testsuite/go.test/test/fixedbugs/bug175.go
gcc/testsuite/go.test/test/fixedbugs/bug200.go
gcc/testsuite/go.test/test/fixedbugs/bug213.go
gcc/testsuite/go.test/test/fixedbugs/bug248.dir/bug2.go
gcc/testsuite/go.test/test/fixedbugs/bug309.go
gcc/testsuite/go.test/test/fixedbugs/bug363.go
gcc/testsuite/go.test/test/func4.go
gcc/testsuite/go.test/test/indirect1.go
libgo/go/io/ioutil/ioutil_test.go
libgo/go/reflect/type.go
libgo/go/reflect/value.go

index fe361fb..ebecbbd 100644 (file)
@@ -1472,6 +1472,7 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
               real->message_name().c_str());
       return Expression::make_error(location);
     case Named_object::NAMED_OBJECT_VAR:
+      real->var_value()->set_is_used();
       return Expression::make_var_reference(real, location);
     case Named_object::NAMED_OBJECT_FUNC:
     case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
index e995be4..61d1bd8 100644 (file)
@@ -1036,6 +1036,23 @@ Gogo::add_named_object(Named_object* no)
   this->current_bindings()->add_named_object(no);
 }
 
+// Mark all local variables used.  This is used when some types of
+// parse error occur.
+
+void
+Gogo::mark_locals_used()
+{
+  for (Open_functions::iterator pf = this->functions_.begin();
+       pf != this->functions_.end();
+       ++pf)
+    {
+      for (std::vector<Block*>::iterator pb = pf->blocks.begin();
+          pb != pf->blocks.end();
+          ++pb)
+       (*pb)->bindings()->mark_locals_used();
+    }
+}
+
 // Record that we've seen an interface type.
 
 void
@@ -1731,6 +1748,15 @@ Check_types_traverse::variable(Named_object* named_object)
                     reason.c_str());
          var->clear_init();
        }
+      else if (!var->is_used()
+              && !var->is_global()
+              && !var->is_parameter()
+              && !var->is_receiver()
+              && !var->type()->is_error()
+              && (init == NULL || !init->is_error_expression())
+              && !Lex::is_invalid_identifier(named_object->name()))
+       error_at(var->location(), "%qs declared and not used",
+                named_object->message_name().c_str());
     }
   return TRAVERSE_CONTINUE;
 }
@@ -2973,6 +2999,7 @@ Function::closure_var()
       Type* struct_type = Type::make_struct_type(sfl, loc);
       Variable* var = new Variable(Type::make_pointer_type(struct_type),
                                   NULL, false, true, false, loc);
+      var->set_is_used();
       this->closure_var_ = Named_object::make_variable("closure", NULL, var);
       // Note that the new variable is not in any binding contour.
     }
@@ -3693,7 +3720,7 @@ Variable::Variable(Type* type, Expression* init, bool is_global,
                   Location location)
   : type_(type), init_(init), preinit_(NULL), location_(location),
     backend_(NULL), is_global_(is_global), is_parameter_(is_parameter),
-    is_receiver_(is_receiver), is_varargs_parameter_(false),
+    is_receiver_(is_receiver), is_varargs_parameter_(false), is_used_(false),
     is_address_taken_(false), is_non_escaping_address_taken_(false),
     seen_(false), init_is_lowered_(false), type_from_init_tuple_(false),
     type_from_range_index_(false), type_from_range_value_(false),
@@ -4877,6 +4904,19 @@ Bindings::define_type(Named_object* no, Named_type* type)
   this->named_objects_.push_back(no);
 }
 
+// Mark all local variables as used.  This is used for some types of
+// parse error.
+
+void
+Bindings::mark_locals_used()
+{
+  for (std::vector<Named_object*>::iterator p = this->named_objects_.begin();
+       p != this->named_objects_.end();
+       ++p)
+    if ((*p)->is_variable())
+      (*p)->var_value()->set_is_used();
+}
+
 // Traverse bindings.
 
 int
index 1042f03..dfaa596 100644 (file)
@@ -344,6 +344,11 @@ class Gogo
   void
   add_named_object(Named_object*);
 
+  // Mark all local variables in current bindings as used.  This is
+  // used when there is a parse error to avoid useless errors.
+  void
+  mark_locals_used();
+
   // Return a name to use for a thunk function.  A thunk function is
   // one we create during the compilation, for a go statement or a
   // defer statement or a method expression.
@@ -1232,6 +1237,16 @@ class Variable
     this->is_varargs_parameter_ = true;
   }
 
+  // Return whether the variable has been used.
+  bool
+  is_used() const
+  { return this->is_used_; }
+
+  // Mark that the variable has been used.
+  void
+  set_is_used()
+  { this->is_used_ = true; }
+
   // Clear the initial value; used for error handling.
   void
   clear_init()
@@ -1368,6 +1383,8 @@ class Variable
   bool is_receiver_ : 1;
   // Whether this is the varargs parameter of a function.
   bool is_varargs_parameter_ : 1;
+  // Whether this variable is ever referenced.
+  bool is_used_ : 1;
   // Whether something takes the address of this variable.  For a
   // local variable this implies that the variable has to be on the
   // heap.
@@ -2124,6 +2141,11 @@ class Bindings
   void
   remove_binding(Named_object*);
 
+  // Mark all variables as used.  This is used for some types of parse
+  // error.
+  void
+  mark_locals_used();
+
   // Traverse the tree.  See the Traverse class.
   int
   traverse(Traverse*, bool is_global);
index af23e9b..d46334f 100644 (file)
@@ -866,6 +866,7 @@ Lex::gather_identifier()
          this->lineoff_ = p - this->linebuf_;
          const char* pnext = this->advance_one_utf8_char(p, &ci,
                                                          &issued_error);
+         bool is_invalid = false;
          if (!Lex::is_unicode_letter(ci) && !Lex::is_unicode_digit(ci))
            {
              // There is no valid place for a non-ASCII character
@@ -876,6 +877,7 @@ Lex::gather_identifier()
                error_at(this->location(),
                         "invalid character 0x%x in identifier",
                         ci);
+             is_invalid = true;
            }
          if (is_first)
            {
@@ -887,6 +889,8 @@ Lex::gather_identifier()
              buf.assign(pstart, p - pstart);
              has_non_ascii_char = true;
            }
+         if (is_invalid && !Lex::is_invalid_identifier(buf))
+           buf.append("$INVALID$");
          p = pnext;
          char ubuf[50];
          // This assumes that all assemblers can handle an identifier
@@ -2312,3 +2316,13 @@ Lex::is_exported_name(const std::string& name)
       return Lex::is_unicode_uppercase(ci);
     }
 }
+
+// Return whether the identifier NAME contains an invalid character.
+// This is based on how we handle invalid characters in
+// gather_identifier.
+
+bool
+Lex::is_invalid_identifier(const std::string& name)
+{
+  return name.find("$INVALID$") != std::string::npos;
+}
index b9b4b1f..b184b1e 100644 (file)
@@ -349,6 +349,13 @@ class Lex
   static bool
   is_exported_name(const std::string& name);
 
+  // Return whether the identifier NAME is invalid.  When we see an
+  // invalid character we still build an identifier, but we use a
+  // magic string to indicate that the identifier is invalid.  We then
+  // use this to avoid knockon errors.
+  static bool
+  is_invalid_identifier(const std::string& name);
+
   // A helper function.  Append V to STR.  IS_CHARACTER is true if V
   // is a Unicode character which should be converted into UTF-8,
   // false if it is a byte value to be appended directly.  The
index 21cd764..35af758 100644 (file)
@@ -49,7 +49,8 @@ Parse::Parse(Lex* lex, Gogo* gogo)
     break_stack_(NULL),
     continue_stack_(NULL),
     iota_(0),
-    enclosing_vars_()
+    enclosing_vars_(),
+    type_switch_vars_()
 {
 }
 
@@ -539,6 +540,7 @@ Parse::field_decl(Struct_field_list* sfl)
   else
     {
       error_at(this->location(), "expected field name");
+      this->gogo_->mark_locals_used();
       while (!token->is_op(OPERATOR_SEMICOLON)
             && !token->is_op(OPERATOR_RCURLY)
             && !token->is_eof())
@@ -554,6 +556,7 @@ Parse::field_decl(Struct_field_list* sfl)
          if (!this->peek_token()->is_identifier())
            {
              error_at(this->location(), "expected field name");
+             this->gogo_->mark_locals_used();
              while (!token->is_op(OPERATOR_SEMICOLON)
                     && !token->is_op(OPERATOR_RCURLY)
                     && !token->is_eof())
@@ -1123,6 +1126,8 @@ Parse::block()
          if (!token->is_eof() || !saw_errors())
            error_at(this->location(), "expected %<}%>");
 
+         this->gogo_->mark_locals_used();
+
          // Skip ahead to the end of the block, in hopes of avoiding
          // lots of meaningless errors.
          Location ret = token->location();
@@ -1249,6 +1254,7 @@ Parse::method_spec(Typed_identifier_list* methods)
                     "name list not allowed in interface type");
          else
            error_at(location, "expected signature or type name");
+         this->gogo_->mark_locals_used();
          token = this->peek_token();
          while (!token->is_eof()
                 && !token->is_op(OPERATOR_SEMICOLON)
@@ -1498,6 +1504,7 @@ Parse::type_spec(void*)
 
   if (type->is_error_type())
     {
+      this->gogo_->mark_locals_used();
       while (!this->peek_token()->is_op(OPERATOR_SEMICOLON)
             && !this->peek_token()->is_eof())
        this->advance_token();
@@ -1558,6 +1565,7 @@ Parse::var_spec(void*)
       type = this->type();
       if (type->is_error_type())
        {
+         this->gogo_->mark_locals_used();
          while (!this->peek_token()->is_op(OPERATOR_EQ)
                 && !this->peek_token()->is_op(OPERATOR_SEMICOLON)
                 && !this->peek_token()->is_eof())
@@ -1894,6 +1902,7 @@ Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init,
              // initializer can be assigned to the type.
              Variable* var = new Variable(type, init, false, false, false,
                                           location);
+             var->set_is_used();
              static int count;
              char buf[30];
              snprintf(buf, sizeof buf, "sink$%d", count);
@@ -2188,6 +2197,7 @@ Parse::receiver()
       if (!token->is_identifier())
        {
          error_at(this->location(), "method has no receiver");
+         this->gogo_->mark_locals_used();
          while (!token->is_eof() && !token->is_op(OPERATOR_RPAREN))
            token = this->advance_token();
          if (!token->is_eof())
@@ -2227,6 +2237,7 @@ Parse::receiver()
   if (!token->is_identifier())
     {
       error_at(this->location(), "expected receiver name or type");
+      this->gogo_->mark_locals_used();
       int c = token->is_op(OPERATOR_LPAREN) ? 1 : 0;
       while (!token->is_eof())
        {
@@ -2258,6 +2269,7 @@ Parse::receiver()
        error_at(this->location(), "method has multiple receivers");
       else
        error_at(this->location(), "expected %<)%>");
+      this->gogo_->mark_locals_used();
       while (!token->is_eof() && !token->is_op(OPERATOR_RPAREN))
        token = this->advance_token();
       if (!token->is_eof())
@@ -2365,6 +2377,7 @@ Parse::operand(bool may_be_sink)
            }
          case Named_object::NAMED_OBJECT_VAR:
          case Named_object::NAMED_OBJECT_RESULT_VAR:
+           this->mark_var_used(named_object);
            return Expression::make_var_reference(named_object, location);
          case Named_object::NAMED_OBJECT_SINK:
            if (may_be_sink)
@@ -2477,6 +2490,8 @@ Parse::enclosing_var_reference(Named_object* in_function, Named_object* var,
 {
   go_assert(var->is_variable() || var->is_result_variable());
 
+  this->mark_var_used(var);
+
   Named_object* this_function = this->gogo_->current_function();
   Named_object* closure = this_function->func_value()->closure_var();
 
@@ -2648,6 +2663,7 @@ Parse::composite_lit(Type* type, int depth, Location location)
        {
          error_at(this->location(), "expected %<,%> or %<}%>");
 
+         this->gogo_->mark_locals_used();
          int depth = 0;
          while (!token->is_eof()
                 && (depth > 0 || !token->is_op(OPERATOR_RCURLY)))
@@ -3019,6 +3035,7 @@ Parse::id_to_expression(const std::string& name, Location location)
       return Expression::make_const_reference(named_object, location);
     case Named_object::NAMED_OBJECT_VAR:
     case Named_object::NAMED_OBJECT_RESULT_VAR:
+      this->mark_var_used(named_object);
       return Expression::make_var_reference(named_object, location);
     case Named_object::NAMED_OBJECT_SINK:
       return Expression::make_sink(location);
@@ -3534,6 +3551,7 @@ Parse::simple_stat(bool may_be_composite_lit, bool* return_exp,
        {
          if (!exp->is_error_expression())
            error_at(token->location(), "non-name on left side of %<:=%>");
+         this->gogo_->mark_locals_used();
          while (!token->is_op(OPERATOR_SEMICOLON)
                 && !token->is_eof())
            token = this->advance_token();
@@ -4287,7 +4305,15 @@ Parse::type_case_clause(Named_object* switch_no, Type_case_clauses* clauses,
          Variable* v = new Variable(type, init, false, false, false,
                                     location);
          v->set_is_type_switch_var();
-         this->gogo_->add_variable(switch_no->name(), v);
+         Named_object* no = this->gogo_->add_variable(switch_no->name(), v);
+
+         // We don't want to issue an error if the compiler
+         // introduced special variable is not used.  Instead we want
+         // to issue an error if the variable defined by the switch
+         // is not used.  That is handled via type_switch_vars_ and
+         // Parse::mark_var_used.
+         v->set_is_used();
+         this->type_switch_vars_[no] = switch_no;
        }
       this->statement_list();
       statements = this->gogo_->finish_block(this->location());
@@ -4343,6 +4369,7 @@ Parse::type_switch_case(std::vector<Type*>* types, bool* is_default)
            types->push_back(t);
          else
            {
+             this->gogo_->mark_locals_used();
              token = this->peek_token();
              while (!token->is_op(OPERATOR_COLON)
                     && !token->is_op(OPERATOR_COMMA)
@@ -5209,6 +5236,7 @@ Parse::program()
       else
        {
          error_at(this->location(), "expected declaration");
+         this->gogo_->mark_locals_used();
          do
            this->advance_token();
          while (!this->peek_token()->is_eof()
@@ -5267,6 +5295,7 @@ Parse::increment_iota()
 bool
 Parse::skip_past_error(Operator op)
 {
+  this->gogo_->mark_locals_used();
   const Token* token = this->peek_token();
   while (!token->is_op(op))
     {
@@ -5294,3 +5323,22 @@ Parse::verify_not_sink(Expression* expr)
     }
   return expr;
 }
+
+// Mark a variable as used.
+
+void
+Parse::mark_var_used(Named_object* no)
+{
+  if (no->is_variable())
+    {
+      no->var_value()->set_is_used();
+
+      // When a type switch uses := to define a variable, then for
+      // each case with a single type we introduce a new variable with
+      // the appropriate type.  When we do, if the newly introduced
+      // variable is used, then the type switch variable is used.
+      Type_switch_vars::iterator p = this->type_switch_vars_.find(no);
+      if (p != this->type_switch_vars_.end())
+       p->second->var_value()->set_is_used();
+    }
+}
index 0a3fe64..f45aa85 100644 (file)
@@ -155,6 +155,11 @@ class Parse
   // break or continue statement with no label.
   typedef std::vector<std::pair<Statement*, Label*> > Bc_stack;
 
+  // Map from type switch variables to the variables they mask, so
+  // that a use of the type switch variable can become a use of the
+  // real variable.
+  typedef Unordered_map(Named_object*, Named_object*) Type_switch_vars;
+
   // Parser nonterminals.
   void identifier_list(Typed_identifier_list*);
   Expression_list* expression_list(Expression*, bool may_be_sink);
@@ -288,6 +293,10 @@ class Parse
   Statement*
   find_bc_statement(const Bc_stack*, const std::string&) const;
 
+  // Mark a variable as used.
+  void
+  mark_var_used(Named_object*);
+
   // The lexer output we are parsing.
   Lex* lex_;
   // The current token.
@@ -307,6 +316,8 @@ class Parse
   // References from the local function to variables defined in
   // enclosing functions.
   Enclosing_vars enclosing_vars_;
+  // Map from type switch variables to real variables.
+  Type_switch_vars type_switch_vars_;
 };
 
 
index 5bc1efc..bcc7846 100644 (file)
@@ -9,4 +9,5 @@ package _       // ERROR "invalid package name _"
 func main() {
        _()     // ERROR "cannot use _ as value"
        x := _+1        // ERROR "cannot use _ as value"
+       _ = x
 }
index dac2ce5..38a6e51 100644 (file)
@@ -11,4 +11,5 @@ func main() {
        var c01 uint8 = '\07';  // ERROR "oct|char"
        var cx0 uint8 = '\x0';  // ERROR "hex|char"
        var cx1 uint8 = '\x';  // ERROR "hex|char"
+       _, _, _, _ = c00, c01, cx0, cx1
 }
index 5c7649f..10e406d 100644 (file)
@@ -7,4 +7,5 @@
 package main
 func f() {
        v := 1 << 1025;         // ERROR "overflow|stupid shift"
+       _ = v
 }
index 756ba30..1b125e5 100644 (file)
@@ -20,7 +20,7 @@ type Getter interface {
 
 func f1(p Empty) {
        switch x := p.(type) {
-       default: println("failed to match interface"); os.Exit(1);
+       default: println("failed to match interface", x); os.Exit(1);
        case Getter: break;
        }
 
index a8f6e3c..1ca1415 100644 (file)
@@ -10,5 +10,5 @@ func f() (int, bool) { return 0, true }
 
 func main() {
        x, y := f(), 2; // ERROR "multi"
+       _, _ = x, y
 }
-
index 123f687..63b8633 100644 (file)
@@ -12,7 +12,7 @@ func main() {
        // and worse, compiled the wrong code
        // for one of them.
        var x interface{};
-       switch v := x.(type) {
+       switch x.(type) {
        case func(int):
        case func(f int):       // ERROR "duplicate"
        }
index 07d9f90..4d81dbb 100644 (file)
@@ -7,7 +7,7 @@
 package main
 func main() {
        var v interface{} = 0;
-       switch x := v.(type) {
+       switch v.(type) {
        case int:
                fallthrough;            // ERROR "fallthrough"
        default:
index b6c816a..adce366 100644 (file)
@@ -80,7 +80,7 @@ func main() {
                case 2:
                        i = 3.14
                }
-               switch k := i.(type) {
+               switch i.(type) {
                case p0.T:
                        if j != 0 {
                                println("type switch p0.T")
index 07bebae..d893916 100644 (file)
@@ -15,5 +15,7 @@ func foo(t interface{}, c chan int) {
                case <-c:
                        // bug was: internal compiler error: var without type, init: v
                }
+       default:
+               _ = v
        }
 }
index 04fcfe1..9347ec2 100644 (file)
@@ -17,5 +17,5 @@ func main() {
        println(b)
 
        var c int64 = (1<<i) + 4.0  // ok - it's all int64
-       println(b)
+       println(c)
 }
index 69ce56a..2a1a932 100644 (file)
@@ -11,4 +11,5 @@ var notmain func()
 func main() {
        var x = &main           // ERROR "address of|invalid"
        main = notmain  // ERROR "assign to|invalid"
+       _ = x
 }
index 0fd5c19..ecb4f13 100644 (file)
@@ -65,4 +65,5 @@ func f() {
                cap(b2)+        // ERROR "illegal|invalid|must be"
                cap(b3)+
                cap(b4) // ERROR "illegal|invalid|must be"
+       _ = x
 }
index 1030668..70f83c9 100644 (file)
@@ -71,13 +71,13 @@ func TestReadDir(t *testing.T) {
                t.Fatalf("ReadDir %s: error expected, none found", dirname)
        }
 
+       /* Does not work in gccgo testing environment.
        dirname = ".."
        list, err := ReadDir(dirname)
        if err != nil {
                t.Fatalf("ReadDir %s: %v", dirname, err)
        }
 
-/* Does not work in gccgo testing environment.
        foundFile := false
        foundSubDir := false
        for _, dir := range list {
@@ -94,5 +94,5 @@ func TestReadDir(t *testing.T) {
        if !foundSubDir {
                t.Fatalf("ReadDir %s: ioutil directory not found", dirname)
        }
-*/
+       */
 }
index 07cc0f5..a3c5658 100644 (file)
@@ -243,7 +243,7 @@ type commonType struct {
        align      int8
        fieldAlign uint8
        size       uintptr
-       hash       uint32
+       hash       uint32
        hashfn     func(unsafe.Pointer, uintptr)
        equalfn    func(unsafe.Pointer, unsafe.Pointer, uintptr)
        string     *string
@@ -464,7 +464,7 @@ func (t *uncommonType) Method(i int) (m Method) {
        m.Type = mt.toType()
        x := new(unsafe.Pointer)
        *x = p.tfn
-       m.Func = Value{mt, unsafe.Pointer(x), fl|flagIndir}
+       m.Func = Value{mt, unsafe.Pointer(x), fl | flagIndir}
        m.Index = i
        return
 }
@@ -999,10 +999,8 @@ func (ct *commonType) ptrTo() *commonType {
                return &p.commonType
        }
 
-       rt := (*runtime.Type)(unsafe.Pointer(ct))
-
        rp := new(runtime.PtrType)
-       
+
        // initialize p using *byte's ptrType as a prototype.
        // have to do assignment as ptrType, not runtime.PtrType,
        // in order to write to unexported fields.
index f9a3c8a..a1bc334 100644 (file)
@@ -215,8 +215,8 @@ type emptyInterface struct {
 type nonEmptyInterface struct {
        // see ../runtime/iface.c:/Itab
        itab *struct {
-               typ    *runtime.Type // dynamic concrete type
-               fun    [100000]unsafe.Pointer // method table
+               typ *runtime.Type          // dynamic concrete type
+               fun [100000]unsafe.Pointer // method table
        }
        word iword
 }
@@ -448,7 +448,6 @@ func (v Value) call(method string, in []Value) []Value {
                nin++
        }
        params := make([]unsafe.Pointer, nin)
-       delta := 0
        off := 0
        if v.flag&flagMethod != 0 {
                // Hard-wired first argument.
@@ -517,7 +516,7 @@ func isMethod(t *commonType) bool {
                        params++
                } else if c == ')' {
                        parens--
-               } else if parens == 0 && c == ' ' && s[i + 1] != '(' && !sawRet {
+               } else if parens == 0 && c == ' ' && s[i+1] != '(' && !sawRet {
                        params++
                        sawRet = true
                }
@@ -1627,7 +1626,7 @@ func MakeChan(typ Type, buffer int) Value {
                panic("reflect.MakeChan: unidirectional channel type")
        }
        ch := makechan(typ.runtimeType(), uint32(buffer))
-       return Value{typ.common(), unsafe.Pointer(ch), flagIndir | (flag(Chan)<<flagKindShift)}
+       return Value{typ.common(), unsafe.Pointer(ch), flagIndir | (flag(Chan) << flagKindShift)}
 }
 
 // MakeMap creates a new map of the specified type.
@@ -1636,7 +1635,7 @@ func MakeMap(typ Type) Value {
                panic("reflect.MakeMap of non-map type")
        }
        m := makemap(typ.runtimeType())
-       return Value{typ.common(), unsafe.Pointer(m), flagIndir | (flag(Map)<<flagKindShift)}
+       return Value{typ.common(), unsafe.Pointer(m), flagIndir | (flag(Map) << flagKindShift)}
 }
 
 // Indirect returns the value that v points to.