Commit 56bafc49 by Than McIntosh Committed by Ian Lance Taylor

compiler: better abstraction layer for diagnostics.

    
    Introduce an abstraction layer for reporting diagnostics, so as to avoid
    directly using the native GCC interfaces such as "error_at",
    "warning_at", "open_quote", "close_quote", etc.  The new interfaces have
    the same look and feel as the GCC equivalents, but make calls into
    back-end functions to allow the back end to select the proper final
    reporting routine.
    
    Reviewed-on: https://go-review.googlesource.com/29191

	* go-gcc-diagnostics.cc: New file.
	* go-location.h (Location): Remove operator source_location.  Add
	operator==.
	* go-system.h: #include <sstream>.
	* Make-lang.in (GO_OBJS): Add go/go-diagnostics.o and
	go/go-gcc-diagnostics.o.
	(CFLAGS-go/go-gcc-diagnostics.o): New variable.

From-SVN: r240453
parent 34a594e8
2016-09-23 Than McIntosh <thanm@google.com>
* go-gcc-diagnostics.cc: New file.
* go-location.h (Location): Remove operator source_location. Add
operator==.
* go-system.h: #include <sstream>.
* Make-lang.in (GO_OBJS): Add go/go-diagnostics.o and
go/go-gcc-diagnostics.o.
(CFLAGS-go/go-gcc-diagnostics.o): New variable.
2016-09-23 Chris Manghane <cmang@google.com> 2016-09-23 Chris Manghane <cmang@google.com>
PR go/77701 PR go/77701
......
...@@ -54,8 +54,10 @@ GO_OBJS = \ ...@@ -54,8 +54,10 @@ GO_OBJS = \
go/export.o \ go/export.o \
go/expressions.o \ go/expressions.o \
go/go-backend.o \ go/go-backend.o \
go/go-diagnostics.o \
go/go-dump.o \ go/go-dump.o \
go/go-gcc.o \ go/go-gcc.o \
go/go-gcc-diagnostics.o \
go/go-lang.o \ go/go-lang.o \
go/go-linemap.o \ go/go-linemap.o \
go/go-optimize.o \ go/go-optimize.o \
...@@ -227,6 +229,7 @@ GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend ...@@ -227,6 +229,7 @@ GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend
CFLAGS-go/go-gcc.o += $(GOINCLUDES) CFLAGS-go/go-gcc.o += $(GOINCLUDES)
CFLAGS-go/go-linemap.o += $(GOINCLUDES) CFLAGS-go/go-linemap.o += $(GOINCLUDES)
CFLAGS-go/go-sha1.o += $(GOINCLUDES) CFLAGS-go/go-sha1.o += $(GOINCLUDES)
CFLAGS-go/go-gcc-diagnostics.o += $(GOINCLUDES)
go/%.o: go/gofrontend/%.cc go/%.o: go/gofrontend/%.cc
$(COMPILE) $(GOINCLUDES) $< $(COMPILE) $(GOINCLUDES) $<
......
// go-gcc-diagnostics.cc -- GCC implementation of go diagnostics interface.
// Copyright (C) 2016 Free Software Foundation, Inc.
// Contributed by Than McIntosh, Google.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#include "go-system.h"
#include "go-diagnostics.h"
void
go_be_error_at(const Location location, const std::string& errmsg)
{
source_location gcc_loc = location.gcc_location();
error_at(gcc_loc, "%s", errmsg.c_str());
}
void
go_be_warning_at(const Location location,
int opt, const std::string& warningmsg)
{
source_location gcc_loc = location.gcc_location();
warning_at(gcc_loc, opt, "%s", warningmsg.c_str());
}
void
go_be_fatal_error(const Location location,
const std::string& fatalmsg)
{
source_location gcc_loc = location.gcc_location();
fatal_error(gcc_loc, "%s", fatalmsg.c_str());
}
void
go_be_inform(const Location location,
const std::string& infomsg)
{
source_location gcc_loc = location.gcc_location();
inform(gcc_loc, "%s", infomsg.c_str());
}
void
go_be_get_quotechars(const char** open_qu, const char** close_qu)
{
*open_qu = open_quote;
*close_qu = close_quote;
}
...@@ -26,10 +26,6 @@ class Location ...@@ -26,10 +26,6 @@ class Location
gcc_location() const gcc_location() const
{ return this->gcc_loc_; } { return this->gcc_loc_; }
// Temporary hack till error_at and warning_at can deal with a Location.
operator source_location() const
{ return this->gcc_loc_; }
private: private:
source_location gcc_loc_; source_location gcc_loc_;
}; };
...@@ -42,4 +38,10 @@ operator<(Location loca, Location locb) ...@@ -42,4 +38,10 @@ operator<(Location loca, Location locb)
return loca.gcc_location() < locb.gcc_location(); return loca.gcc_location() < locb.gcc_location();
} }
inline bool
operator==(Location loca, Location locb)
{
return loca.gcc_location() == locb.gcc_location();
}
#endif // !defined(GO_LOCATION_H) #endif // !defined(GO_LOCATION_H)
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <map> #include <map>
#include <set> #include <set>
#include <vector> #include <vector>
#include <sstream>
#if defined(HAVE_UNORDERED_MAP) #if defined(HAVE_UNORDERED_MAP)
......
4f84c5e0210e674163f3f6462da6f5be9e5b0a36 57bf3f21005c4508003f65207282c057e3526ec0
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "ast-dump.h" #include "ast-dump.h"
#include "go-c.h" #include "go-c.h"
#include "go-dump.h" #include "go-dump.h"
#include "go-diagnostics.h"
// The -fgo-dump-ast flag to activate AST dumps. // The -fgo-dump-ast flag to activate AST dumps.
...@@ -173,7 +174,8 @@ Ast_dump_context::dump(Gogo* gogo, const char* basename) ...@@ -173,7 +174,8 @@ Ast_dump_context::dump(Gogo* gogo, const char* basename)
if (out.fail()) if (out.fail())
{ {
error("cannot open %s:%m, -fgo-dump-ast ignored", dumpname.c_str()); go_error_at(Linemap::unknown_location(),
"cannot open %s:%m, -fgo-dump-ast ignored", dumpname.c_str());
return; return;
} }
......
...@@ -55,7 +55,7 @@ class Backend ...@@ -55,7 +55,7 @@ class Backend
Location location; Location location;
Btyped_identifier() Btyped_identifier()
: name(), btype(NULL), location(UNKNOWN_LOCATION) : name(), btype(NULL), location(Linemap::unknown_location())
{ } { }
Btyped_identifier(const std::string& a_name, Btype* a_btype, Btyped_identifier(const std::string& a_name, Btype* a_btype,
......
// go-diagnostics.cc -- Go error/warning diagnostics utilities.
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "go-diagnostics.h"
static std::string
mformat_value()
{
return std::string(xstrerror(errno));
}
// Rewrite a format string to expand any extensions not
// supported by sprintf(). See comments in go-diagnostics.h
// for list of supported format specifiers.
static std::string
expand_format(const char* fmt)
{
std::stringstream ss;
for (const char* c = fmt; *c; ++c)
{
if (*c != '%')
{
ss << *c;
continue;
}
c++;
switch (*c)
{
case '\0':
{
// malformed format string
go_unreachable();
}
case '%':
{
ss << "%";
break;
}
case 'm':
{
ss << mformat_value();
break;
}
case '<':
{
ss << go_open_quote();
break;
}
case '>':
{
ss << go_close_quote();
break;
}
case 'q':
{
ss << go_open_quote();
c++;
if (*c == 'm')
{
ss << mformat_value();
}
else
{
ss << "%" << *c;
}
ss << go_close_quote();
break;
}
default:
{
ss << "%" << *c;
}
}
}
return ss.str();
}
// Expand message format specifiers, using a combination of
// expand_format above to handle extensions (ex: %m, %q) and vasprintf()
// to handle regular printf-style formatting. A pragma is being used here to
// suppress this warning:
//
// warning: function ‘std::__cxx11::string expand_message(const char*, __va_list_tag*)’ might be a candidate for ‘gnu_printf’ format attribute [-Wsuggest-attribute=format]
//
// What appears to be happening here is that the checker is deciding that
// because of the call to vasprintf() (which has attribute gnu_printf), the
// calling function must need to have attribute gnu_printf as well, even
// though there is already an attribute declaration for it.
static std::string
expand_message(const char* fmt, va_list ap) GO_ATTRIBUTE_GCC_DIAG(1,0);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
static std::string
expand_message(const char* fmt, va_list ap)
{
char* mbuf = 0;
std::string expanded_fmt = expand_format(fmt);
int nwr = vasprintf(&mbuf, expanded_fmt.c_str(), ap);
if (nwr == -1)
{
// memory allocation failed
go_be_error_at(Linemap::unknown_location(),
"memory allocation failed in vasprintf");
go_assert(0);
}
std::string rval = std::string(mbuf);
free(mbuf);
return rval;
}
#pragma GCC diagnostic pop
static const char* cached_open_quote = NULL;
static const char* cached_close_quote = NULL;
const char*
go_open_quote()
{
if (cached_open_quote == NULL)
go_be_get_quotechars(&cached_open_quote, &cached_close_quote);
return cached_open_quote;
}
const char*
go_close_quote()
{
if (cached_close_quote == NULL)
go_be_get_quotechars(&cached_open_quote, &cached_close_quote);
return cached_close_quote;
}
void
go_error_at(const Location location, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
go_be_error_at(location, expand_message(fmt, ap));
va_end(ap);
}
void
go_warning_at(const Location location, int opt, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
go_be_warning_at(location, opt, expand_message(fmt, ap));
va_end(ap);
}
void
go_fatal_error(const Location location, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
go_be_fatal_error(location, expand_message(fmt, ap));
va_end(ap);
}
void
go_inform(const Location location, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
go_be_inform(location, expand_message(fmt, ap));
va_end(ap);
}
// go-diagnostics.h -- interface to diagnostic reporting -*- C++ -*-
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#ifndef GO_DIAGNOSTICS_H
#define GO_DIAGNOSTICS_H
#include "go-linemap.h"
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
#define GO_ATTRIBUTE_GCC_DIAG(m, n) __attribute__ ((__format__ (__gcc_tdiag__, m, n))) __attribute__ ((__nonnull__ (m)))
#else
#define GO_ATTRIBUTE_GCC_DIAG(m, n)
#endif
// These declarations define the interface through which the frontend
// reports errors and warnings. These functions accept printf-like
// format specifiers (e.g. %d, %f, %s, etc), with the following additional
// extensions:
//
// 1. 'q' qualifier may be applied to a specifier to add quoting, e.g.
// %qd produces a quoted decimal output, %qs a quoted string output.
// [This extension is supported only with single-character format
// specifiers].
//
// 2. %m specifier outputs value of "strerror(errno)" at time of call.
//
// 3. %< outputs an opening quote, %> a closing quote.
//
// All other format specifiers are as defined by 'sprintf'. The final resulting
// message is then sent to the back end via go_be_error_at/go_be_warning_at.
extern void go_error_at(const Location, const char* fmt, ...)
GO_ATTRIBUTE_GCC_DIAG(2,3);
extern void go_warning_at(const Location, int opt, const char* fmt, ...)
GO_ATTRIBUTE_GCC_DIAG(3,4);
extern void go_fatal_error(const Location, const char* fmt, ...)
GO_ATTRIBUTE_GCC_DIAG(2,3);
extern void go_inform(const Location, const char* fmt, ...)
GO_ATTRIBUTE_GCC_DIAG(2,3);
// These interfaces provide a way for the front end to ask for
// the open/close quote characters it should use when formatting
// diagnostics (warnings, errors).
extern const char* go_open_quote();
extern const char* go_close_quote();
// These interfaces are used by utilities above to pass warnings and
// errors (once format specifiers have been expanded) to the back end,
// and to determine quoting style. Avoid calling these routines directly;
// instead use the equivalent routines above. The back end is required to
// implement these routines.
extern void go_be_error_at(const Location, const std::string& errmsg);
extern void go_be_warning_at(const Location, int opt,
const std::string& warningmsg);
extern void go_be_fatal_error(const Location, const std::string& errmsg);
extern void go_be_inform(const Location, const std::string& infomsg);
extern void go_be_get_quotechars(const char** open_quote,
const char** close_quote);
#endif // !defined(GO_DIAGNOSTICS_H)
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "go-system.h" #include "go-system.h"
#include "go-c.h" #include "go-c.h"
#include "go-diagnostics.h"
#include "lex.h" #include "lex.h"
#include "parse.h" #include "parse.h"
...@@ -68,7 +69,7 @@ go_parse_input_files(const char** filenames, unsigned int filename_count, ...@@ -68,7 +69,7 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
{ {
file = fopen(filename, "r"); file = fopen(filename, "r");
if (file == NULL) if (file == NULL)
fatal_error(Linemap::unknown_location(), go_fatal_error(Linemap::unknown_location(),
"cannot open %s: %m", filename); "cannot open %s: %m", filename);
} }
...@@ -88,7 +89,7 @@ go_parse_input_files(const char** filenames, unsigned int filename_count, ...@@ -88,7 +89,7 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
for (Lex::Linknames::const_iterator p = linknames->begin(); for (Lex::Linknames::const_iterator p = linknames->begin();
p != linknames->end(); p != linknames->end();
++p) ++p)
error_at(p->second.loc, go_error_at(p->second.loc,
("//go:linkname only allowed in Go files that " ("//go:linkname only allowed in Go files that "
"import \"unsafe\"")); "import \"unsafe\""));
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "go-system.h" #include "go-system.h"
#include "go-diagnostics.h"
#include "import.h" #include "import.h"
#ifndef O_BINARY #ifndef O_BINARY
...@@ -144,7 +145,7 @@ Archive_file::initialize() ...@@ -144,7 +145,7 @@ Archive_file::initialize()
struct stat st; struct stat st;
if (fstat(this->fd_, &st) < 0) if (fstat(this->fd_, &st) < 0)
{ {
error_at(this->location_, "%s: %m", this->filename_.c_str()); go_error_at(this->location_, "%s: %m", this->filename_.c_str());
return false; return false;
} }
this->filesize_ = st.st_size; this->filesize_ = st.st_size;
...@@ -153,7 +154,7 @@ Archive_file::initialize() ...@@ -153,7 +154,7 @@ Archive_file::initialize()
if (::lseek(this->fd_, 0, SEEK_SET) < 0 if (::lseek(this->fd_, 0, SEEK_SET) < 0
|| ::read(this->fd_, buf, sizeof(armagt)) != sizeof(armagt)) || ::read(this->fd_, buf, sizeof(armagt)) != sizeof(armagt))
{ {
error_at(this->location_, "%s: %m", this->filename_.c_str()); go_error_at(this->location_, "%s: %m", this->filename_.c_str());
return false; return false;
} }
this->is_thin_archive_ = memcmp(buf, armagt, sizeof(armagt)) == 0; this->is_thin_archive_ = memcmp(buf, armagt, sizeof(armagt)) == 0;
...@@ -183,7 +184,7 @@ Archive_file::initialize() ...@@ -183,7 +184,7 @@ Archive_file::initialize()
char* rdbuf = new char[size]; char* rdbuf = new char[size];
if (::read(this->fd_, rdbuf, size) != size) if (::read(this->fd_, rdbuf, size) != size)
{ {
error_at(this->location_, "%s: could not read extended names", go_error_at(this->location_, "%s: could not read extended names",
filename.c_str()); filename.c_str());
delete[] rdbuf; delete[] rdbuf;
return false; return false;
...@@ -203,7 +204,7 @@ Archive_file::read(off_t offset, off_t size, char* buf) ...@@ -203,7 +204,7 @@ Archive_file::read(off_t offset, off_t size, char* buf)
if (::lseek(this->fd_, offset, SEEK_SET) < 0 if (::lseek(this->fd_, offset, SEEK_SET) < 0
|| ::read(this->fd_, buf, size) != size) || ::read(this->fd_, buf, size) != size)
{ {
error_at(this->location_, "%s: %m", this->filename_.c_str()); go_error_at(this->location_, "%s: %m", this->filename_.c_str());
return false; return false;
} }
return true; return true;
...@@ -219,19 +220,19 @@ Archive_file::read_header(off_t off, std::string* pname, off_t* size, ...@@ -219,19 +220,19 @@ Archive_file::read_header(off_t off, std::string* pname, off_t* size,
Archive_header hdr; Archive_header hdr;
if (::lseek(this->fd_, off, SEEK_SET) < 0) if (::lseek(this->fd_, off, SEEK_SET) < 0)
{ {
error_at(this->location_, "%s: %m", this->filename_.c_str()); go_error_at(this->location_, "%s: %m", this->filename_.c_str());
return false; return false;
} }
ssize_t got = ::read(this->fd_, &hdr, sizeof hdr); ssize_t got = ::read(this->fd_, &hdr, sizeof hdr);
if (got != sizeof hdr) if (got != sizeof hdr)
{ {
if (got < 0) if (got < 0)
error_at(this->location_, "%s: %m", this->filename_.c_str()); go_error_at(this->location_, "%s: %m", this->filename_.c_str());
else if (got > 0) else if (got > 0)
error_at(this->location_, "%s: short archive header at %ld", go_error_at(this->location_, "%s: short archive header at %ld",
this->filename_.c_str(), static_cast<long>(off)); this->filename_.c_str(), static_cast<long>(off));
else else
error_at(this->location_, "%s: unexpected EOF at %ld", go_error_at(this->location_, "%s: unexpected EOF at %ld",
this->filename_.c_str(), static_cast<long>(off)); this->filename_.c_str(), static_cast<long>(off));
} }
off_t local_nested_off; off_t local_nested_off;
...@@ -252,7 +253,7 @@ Archive_file::interpret_header(const Archive_header* hdr, off_t off, ...@@ -252,7 +253,7 @@ Archive_file::interpret_header(const Archive_header* hdr, off_t off,
{ {
if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0) if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
{ {
error_at(this->location_, "%s: malformed archive header at %lu", go_error_at(this->location_, "%s: malformed archive header at %lu",
this->filename_.c_str(), static_cast<unsigned long>(off)); this->filename_.c_str(), static_cast<unsigned long>(off));
return false; return false;
} }
...@@ -272,7 +273,7 @@ Archive_file::interpret_header(const Archive_header* hdr, off_t off, ...@@ -272,7 +273,7 @@ Archive_file::interpret_header(const Archive_header* hdr, off_t off,
|| *size < 0 || *size < 0
|| (*size == LONG_MAX && errno == ERANGE)) || (*size == LONG_MAX && errno == ERANGE))
{ {
error_at(this->location_, "%s: malformed archive header size at %lu", go_error_at(this->location_, "%s: malformed archive header size at %lu",
this->filename_.c_str(), static_cast<unsigned long>(off)); this->filename_.c_str(), static_cast<unsigned long>(off));
return false; return false;
} }
...@@ -284,7 +285,8 @@ Archive_file::interpret_header(const Archive_header* hdr, off_t off, ...@@ -284,7 +285,8 @@ Archive_file::interpret_header(const Archive_header* hdr, off_t off,
if (name_end == NULL if (name_end == NULL
|| name_end - hdr->ar_name >= static_cast<int>(sizeof hdr->ar_name)) || name_end - hdr->ar_name >= static_cast<int>(sizeof hdr->ar_name))
{ {
error_at(this->location_, "%s: malformed archive header name at %lu", go_error_at(this->location_,
"%s: malformed archive header name at %lu",
this->filename_.c_str(), static_cast<unsigned long>(off)); this->filename_.c_str(), static_cast<unsigned long>(off));
return false; return false;
} }
...@@ -321,7 +323,7 @@ Archive_file::interpret_header(const Archive_header* hdr, off_t off, ...@@ -321,7 +323,7 @@ Archive_file::interpret_header(const Archive_header* hdr, off_t off,
|| (x == LONG_MAX && errno == ERANGE) || (x == LONG_MAX && errno == ERANGE)
|| static_cast<size_t>(x) >= this->extended_names_.size()) || static_cast<size_t>(x) >= this->extended_names_.size())
{ {
error_at(this->location_, "%s: bad extended name index at %lu", go_error_at(this->location_, "%s: bad extended name index at %lu",
this->filename_.c_str(), static_cast<unsigned long>(off)); this->filename_.c_str(), static_cast<unsigned long>(off));
return false; return false;
} }
...@@ -331,7 +333,8 @@ Archive_file::interpret_header(const Archive_header* hdr, off_t off, ...@@ -331,7 +333,8 @@ Archive_file::interpret_header(const Archive_header* hdr, off_t off,
if (static_cast<size_t>(name_end - name) > this->extended_names_.size() if (static_cast<size_t>(name_end - name) > this->extended_names_.size()
|| name_end[-1] != '/') || name_end[-1] != '/')
{ {
error_at(this->location_, "%s: bad extended name entry at header %lu", go_error_at(this->location_,
"%s: bad extended name entry at header %lu",
this->filename_.c_str(), static_cast<unsigned long>(off)); this->filename_.c_str(), static_cast<unsigned long>(off));
return false; return false;
} }
...@@ -380,7 +383,7 @@ Archive_file::get_file_and_offset(off_t off, const std::string& hdrname, ...@@ -380,7 +383,7 @@ Archive_file::get_file_and_offset(off_t off, const std::string& hdrname,
int nfd = open(filename.c_str(), O_RDONLY | O_BINARY); int nfd = open(filename.c_str(), O_RDONLY | O_BINARY);
if (nfd < 0) if (nfd < 0)
{ {
error_at(this->location_, "%s: can't open nested archive %s", go_error_at(this->location_, "%s: can't open nested archive %s",
this->filename_.c_str(), filename.c_str()); this->filename_.c_str(), filename.c_str());
return false; return false;
} }
...@@ -406,7 +409,7 @@ Archive_file::get_file_and_offset(off_t off, const std::string& hdrname, ...@@ -406,7 +409,7 @@ Archive_file::get_file_and_offset(off_t off, const std::string& hdrname,
*memfd = open(filename.c_str(), O_RDONLY | O_BINARY); *memfd = open(filename.c_str(), O_RDONLY | O_BINARY);
if (*memfd < 0) if (*memfd < 0)
{ {
error_at(this->location_, "%s: %m", filename.c_str()); go_error_at(this->location_, "%s: %m", filename.c_str());
return false; return false;
} }
*memoff = 0; *memoff = 0;
...@@ -499,7 +502,7 @@ Archive_iterator::read_next_header() ...@@ -499,7 +502,7 @@ Archive_iterator::read_next_header()
{ {
if (filesize != this->off_) if (filesize != this->off_)
{ {
error_at(this->afile_->location(), go_error_at(this->afile_->location(),
"%s: short archive header at %lu", "%s: short archive header at %lu",
this->afile_->filename().c_str(), this->afile_->filename().c_str(),
static_cast<unsigned long>(this->off_)); static_cast<unsigned long>(this->off_));
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "filenames.h" #include "filenames.h"
#include "go-c.h" #include "go-c.h"
#include "go-diagnostics.h"
#include "gogo.h" #include "gogo.h"
#include "lex.h" #include "lex.h"
#include "types.h" #include "types.h"
...@@ -132,7 +133,7 @@ Import::try_package_in_directory(const std::string& filename, ...@@ -132,7 +133,7 @@ Import::try_package_in_directory(const std::string& filename,
if (fd < 0) if (fd < 0)
{ {
if (errno != ENOENT && errno != EISDIR) if (errno != ENOENT && errno != EISDIR)
warning_at(location, 0, "%s: %m", filename.c_str()); go_warning_at(location, 0, "%s: %m", filename.c_str());
fd = Import::try_suffixes(&found_filename); fd = Import::try_suffixes(&found_filename);
if (fd < 0) if (fd < 0)
...@@ -146,7 +147,7 @@ Import::try_package_in_directory(const std::string& filename, ...@@ -146,7 +147,7 @@ Import::try_package_in_directory(const std::string& filename,
close(fd); close(fd);
error_at(location, "%s exists but does not contain any Go export data", go_error_at(location, "%s exists but does not contain any Go export data",
found_filename.c_str()); found_filename.c_str());
return NULL; return NULL;
...@@ -211,7 +212,7 @@ Import::find_export_data(const std::string& filename, int fd, Location location) ...@@ -211,7 +212,7 @@ Import::find_export_data(const std::string& filename, int fd, Location location)
if (lseek(fd, 0, SEEK_SET) < 0) if (lseek(fd, 0, SEEK_SET) < 0)
{ {
error_at(location, "lseek %s failed: %m", filename.c_str()); go_error_at(location, "lseek %s failed: %m", filename.c_str());
return NULL; return NULL;
} }
...@@ -247,9 +248,9 @@ Import::find_object_export_data(const std::string& filename, ...@@ -247,9 +248,9 @@ Import::find_object_export_data(const std::string& filename,
if (errmsg != NULL) if (errmsg != NULL)
{ {
if (err == 0) if (err == 0)
error_at(location, "%s: %s", filename.c_str(), errmsg); go_error_at(location, "%s: %s", filename.c_str(), errmsg);
else else
error_at(location, "%s: %s: %s", filename.c_str(), errmsg, go_error_at(location, "%s: %s: %s", filename.c_str(), errmsg,
xstrerror(err)); xstrerror(err));
return NULL; return NULL;
} }
...@@ -307,7 +308,7 @@ Import::import(Gogo* gogo, const std::string& local_name, ...@@ -307,7 +308,7 @@ Import::import(Gogo* gogo, const std::string& local_name,
} }
else else
{ {
error_at(this->location_, go_error_at(this->location_,
("error in import data at %d: invalid magic string"), ("error in import data at %d: invalid magic string"),
stream->pos()); stream->pos());
return NULL; return NULL;
...@@ -382,7 +383,7 @@ Import::import(Gogo* gogo, const std::string& local_name, ...@@ -382,7 +383,7 @@ Import::import(Gogo* gogo, const std::string& local_name,
break; break;
else else
{ {
error_at(this->location_, go_error_at(this->location_,
("error in import data at %d: " ("error in import data at %d: "
"expected %<const%>, %<type%>, %<var%>, " "expected %<const%>, %<type%>, %<var%>, "
"%<func%>, or %<checksum%>"), "%<func%>, or %<checksum%>"),
...@@ -664,7 +665,7 @@ Import::read_type() ...@@ -664,7 +665,7 @@ Import::read_type()
: (static_cast<size_t>(index) >= this->types_.size() : (static_cast<size_t>(index) >= this->types_.size()
|| this->types_[index] == NULL)) || this->types_[index] == NULL))
{ {
error_at(this->location_, go_error_at(this->location_,
"error in import data at %d: bad type index %d", "error in import data at %d: bad type index %d",
stream->pos(), index); stream->pos(), index);
stream->set_saw_error(); stream->set_saw_error();
...@@ -677,7 +678,7 @@ Import::read_type() ...@@ -677,7 +678,7 @@ Import::read_type()
if (c != ' ') if (c != ' ')
{ {
if (!stream->saw_error()) if (!stream->saw_error())
error_at(this->location_, go_error_at(this->location_,
"error in import data at %d: expect %< %> or %<>%>'", "error in import data at %d: expect %< %> or %<>%>'",
stream->pos()); stream->pos());
stream->set_saw_error(); stream->set_saw_error();
...@@ -689,7 +690,7 @@ Import::read_type() ...@@ -689,7 +690,7 @@ Import::read_type()
|| (static_cast<size_t>(index) < this->types_.size() || (static_cast<size_t>(index) < this->types_.size()
&& this->types_[index] != NULL)) && this->types_[index] != NULL))
{ {
error_at(this->location_, go_error_at(this->location_,
"error in import data at %d: type index already defined", "error in import data at %d: type index already defined",
stream->pos()); stream->pos());
stream->set_saw_error(); stream->set_saw_error();
...@@ -768,7 +769,7 @@ Import::read_type() ...@@ -768,7 +769,7 @@ Import::read_type()
no = package->add_type_declaration(type_name, this->location_); no = package->add_type_declaration(type_name, this->location_);
else if (!no->is_type_declaration() && !no->is_type()) else if (!no->is_type_declaration() && !no->is_type())
{ {
error_at(this->location_, "imported %<%s.%s%> both type and non-type", go_error_at(this->location_, "imported %<%s.%s%> both type and non-type",
pkgpath.c_str(), Gogo::message_name(type_name).c_str()); pkgpath.c_str(), Gogo::message_name(type_name).c_str());
stream->set_saw_error(); stream->set_saw_error();
return Type::make_error_type(); return Type::make_error_type();
...@@ -866,8 +867,9 @@ Import::read_escape() ...@@ -866,8 +867,9 @@ Import::read_escape()
if (c != '>') if (c != '>')
{ {
error_at(this->location(), go_error_at(this->location(),
"error in import data at %d: expect %< %> or %<>%>, got %c", ("error in import data at %d: "
"expect %< %> or %<>%>, got %c"),
stream->pos(), c); stream->pos(), c);
stream->set_saw_error(); stream->set_saw_error();
stream->advance(1); stream->advance(1);
...@@ -961,7 +963,7 @@ Import::string_to_int(const std::string &s, bool is_neg_ok, int* ret) ...@@ -961,7 +963,7 @@ Import::string_to_int(const std::string &s, bool is_neg_ok, int* ret)
long prio = strtol(s.c_str(), &end, 10); long prio = strtol(s.c_str(), &end, 10);
if (*end != '\0' || prio > 0x7fffffff || (prio < 0 && !is_neg_ok)) if (*end != '\0' || prio > 0x7fffffff || (prio < 0 && !is_neg_ok))
{ {
error_at(this->location_, "invalid integer in import data at %d", go_error_at(this->location_, "invalid integer in import data at %d",
this->stream_->pos()); this->stream_->pos());
this->stream_->set_saw_error(); this->stream_->set_saw_error();
return false; return false;
...@@ -1018,7 +1020,7 @@ Import::Stream::require_bytes(Location location, const char* bytes, ...@@ -1018,7 +1020,7 @@ Import::Stream::require_bytes(Location location, const char* bytes,
|| memcmp(bytes, read, length) != 0) || memcmp(bytes, read, length) != 0)
{ {
if (!this->saw_error_) if (!this->saw_error_)
error_at(location, "import error at %d: expected %<%.*s%>", go_error_at(location, "import error at %d: expected %<%.*s%>",
this->pos(), static_cast<int>(length), bytes); this->pos(), static_cast<int>(length), bytes);
this->saw_error_ = true; this->saw_error_ = true;
return; return;
...@@ -1033,7 +1035,7 @@ Stream_from_file::Stream_from_file(int fd) ...@@ -1033,7 +1035,7 @@ Stream_from_file::Stream_from_file(int fd)
{ {
if (lseek(fd, 0, SEEK_SET) != 0) if (lseek(fd, 0, SEEK_SET) != 0)
{ {
error("lseek failed: %m"); go_fatal_error(Linemap::unknown_location(), "lseek failed: %m");
this->set_saw_error(); this->set_saw_error();
} }
} }
...@@ -1061,7 +1063,7 @@ Stream_from_file::do_peek(size_t length, const char** bytes) ...@@ -1061,7 +1063,7 @@ Stream_from_file::do_peek(size_t length, const char** bytes)
if (got < 0) if (got < 0)
{ {
if (!this->saw_error()) if (!this->saw_error())
error("read failed: %m"); go_fatal_error(Linemap::unknown_location(), "read failed: %m");
this->set_saw_error(); this->set_saw_error();
return false; return false;
} }
...@@ -1069,7 +1071,7 @@ Stream_from_file::do_peek(size_t length, const char** bytes) ...@@ -1069,7 +1071,7 @@ Stream_from_file::do_peek(size_t length, const char** bytes)
if (lseek(this->fd_, - got, SEEK_CUR) != 0) if (lseek(this->fd_, - got, SEEK_CUR) != 0)
{ {
if (!this->saw_error()) if (!this->saw_error())
error("lseek failed: %m"); go_fatal_error(Linemap::unknown_location(), "lseek failed: %m");
this->set_saw_error(); this->set_saw_error();
return false; return false;
} }
...@@ -1091,7 +1093,7 @@ Stream_from_file::do_advance(size_t skip) ...@@ -1091,7 +1093,7 @@ Stream_from_file::do_advance(size_t skip)
if (lseek(this->fd_, skip, SEEK_CUR) != 0) if (lseek(this->fd_, skip, SEEK_CUR) != 0)
{ {
if (!this->saw_error()) if (!this->saw_error())
error("lseek failed: %m"); go_fatal_error(Linemap::unknown_location(), "lseek failed: %m");
this->set_saw_error(); this->set_saw_error();
} }
if (!this->data_.empty()) if (!this->data_.empty())
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
#include "go-system.h" #include "go-system.h"
#include "go-diagnostics.h"
#include "lex.h" #include "lex.h"
...@@ -477,7 +478,7 @@ Lex::get_line() ...@@ -477,7 +478,7 @@ Lex::get_line()
{ {
size_t ns = 2 * size + 1; size_t ns = 2 * size + 1;
if (ns < size || static_cast<ssize_t>(ns) < 0) if (ns < size || static_cast<ssize_t>(ns) < 0)
error_at(this->location(), "out of memory"); go_error_at(this->location(), "out of memory");
char* nb = new char[ns]; char* nb = new char[ns];
memcpy(nb, buf, cur); memcpy(nb, buf, cur);
delete[] buf; delete[] buf;
...@@ -743,7 +744,7 @@ Lex::next_token() ...@@ -743,7 +744,7 @@ Lex::next_token()
return this->gather_identifier(); return this->gather_identifier();
if (!issued_error) if (!issued_error)
error_at(this->location(), go_error_at(this->location(),
"invalid character 0x%x in input file", "invalid character 0x%x in input file",
ci); ci);
...@@ -834,7 +835,7 @@ Lex::advance_one_utf8_char(const char* p, unsigned int* value, ...@@ -834,7 +835,7 @@ Lex::advance_one_utf8_char(const char* p, unsigned int* value,
if (*p == '\0') if (*p == '\0')
{ {
error_at(this->location(), "invalid NUL byte"); go_error_at(this->location(), "invalid NUL byte");
*issued_error = true; *issued_error = true;
*value = 0; *value = 0;
return p + 1; return p + 1;
...@@ -843,7 +844,7 @@ Lex::advance_one_utf8_char(const char* p, unsigned int* value, ...@@ -843,7 +844,7 @@ Lex::advance_one_utf8_char(const char* p, unsigned int* value,
int adv = Lex::fetch_char(p, value); int adv = Lex::fetch_char(p, value);
if (adv == 0) if (adv == 0)
{ {
error_at(this->location(), "invalid UTF-8 encoding"); go_error_at(this->location(), "invalid UTF-8 encoding");
*issued_error = true; *issued_error = true;
return p + 1; return p + 1;
} }
...@@ -851,7 +852,7 @@ Lex::advance_one_utf8_char(const char* p, unsigned int* value, ...@@ -851,7 +852,7 @@ Lex::advance_one_utf8_char(const char* p, unsigned int* value,
// Warn about byte order mark, except at start of file. // Warn about byte order mark, except at start of file.
if (*value == 0xfeff && (this->lineno_ != 1 || this->lineoff_ != 0)) if (*value == 0xfeff && (this->lineno_ != 1 || this->lineoff_ != 0))
{ {
error_at(this->location(), "Unicode (UTF-8) BOM in middle of file"); go_error_at(this->location(), "Unicode (UTF-8) BOM in middle of file");
*issued_error = true; *issued_error = true;
} }
...@@ -890,7 +891,7 @@ Lex::gather_identifier() ...@@ -890,7 +891,7 @@ Lex::gather_identifier()
break; break;
this->lineoff_ = p - this->linebuf_; this->lineoff_ = p - this->linebuf_;
error_at(this->location(), go_error_at(this->location(),
"invalid character 0x%x in identifier", "invalid character 0x%x in identifier",
cc); cc);
if (!has_non_ascii_char) if (!has_non_ascii_char)
...@@ -925,7 +926,7 @@ Lex::gather_identifier() ...@@ -925,7 +926,7 @@ Lex::gather_identifier()
// handling behavior if we swallow this character after // handling behavior if we swallow this character after
// giving an error. // giving an error.
if (!issued_error) if (!issued_error)
error_at(this->location(), go_error_at(this->location(),
"invalid character 0x%x in identifier", "invalid character 0x%x in identifier",
ci); ci);
is_invalid = true; is_invalid = true;
...@@ -1109,9 +1110,9 @@ Lex::gather_number() ...@@ -1109,9 +1110,9 @@ Lex::gather_number()
if (r != 0) if (r != 0)
{ {
if (base == 8) if (base == 8)
error_at(this->location(), "invalid octal literal"); go_error_at(this->location(), "invalid octal literal");
else else
error_at(this->location(), "invalid hex literal"); go_error_at(this->location(), "invalid hex literal");
} }
if (neg) if (neg)
...@@ -1225,7 +1226,7 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value, ...@@ -1225,7 +1226,7 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value,
if (is_single_quote if (is_single_quote
&& (*value == '\'' || *value == '\n') && (*value == '\'' || *value == '\n')
&& !issued_error) && !issued_error)
error_at(this->location(), "invalid character literal"); go_error_at(this->location(), "invalid character literal");
return ret; return ret;
} }
else else
...@@ -1244,12 +1245,12 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value, ...@@ -1244,12 +1245,12 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value,
+ Lex::octal_value(p[2])); + Lex::octal_value(p[2]));
if (*value > 255) if (*value > 255)
{ {
error_at(this->location(), "invalid octal constant"); go_error_at(this->location(), "invalid octal constant");
*value = 255; *value = 255;
} }
return p + 3; return p + 3;
} }
error_at(this->location(), "invalid octal character"); go_error_at(this->location(), "invalid octal character");
return (p[1] >= '0' && p[1] <= '7' return (p[1] >= '0' && p[1] <= '7'
? p + 2 ? p + 2
: p + 1); : p + 1);
...@@ -1261,7 +1262,7 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value, ...@@ -1261,7 +1262,7 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value,
*value = (Lex::hex_val(p[1]) << 4) + Lex::hex_val(p[2]); *value = (Lex::hex_val(p[1]) << 4) + Lex::hex_val(p[2]);
return p + 3; return p + 3;
} }
error_at(this->location(), "invalid hex character"); go_error_at(this->location(), "invalid hex character");
return (Lex::is_hex_digit(p[1]) return (Lex::is_hex_digit(p[1])
? p + 2 ? p + 2
: p + 1); : p + 1);
...@@ -1292,12 +1293,12 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value, ...@@ -1292,12 +1293,12 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value,
return p + 1; return p + 1;
case '\'': case '\'':
if (!is_single_quote) if (!is_single_quote)
error_at(this->location(), "invalid quoted character"); go_error_at(this->location(), "invalid quoted character");
*value = '\''; *value = '\'';
return p + 1; return p + 1;
case '"': case '"':
if (is_single_quote) if (is_single_quote)
error_at(this->location(), "invalid quoted character"); go_error_at(this->location(), "invalid quoted character");
*value = '"'; *value = '"';
return p + 1; return p + 1;
...@@ -1311,7 +1312,7 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value, ...@@ -1311,7 +1312,7 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value,
+ Lex::hex_val(p[4])); + Lex::hex_val(p[4]));
if (*value >= 0xd800 && *value < 0xe000) if (*value >= 0xd800 && *value < 0xe000)
{ {
error_at(this->location(), go_error_at(this->location(),
"invalid unicode code point 0x%x", "invalid unicode code point 0x%x",
*value); *value);
// Use the replacement character. // Use the replacement character.
...@@ -1319,7 +1320,7 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value, ...@@ -1319,7 +1320,7 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value,
} }
return p + 5; return p + 5;
} }
error_at(this->location(), "invalid little unicode code point"); go_error_at(this->location(), "invalid little unicode code point");
return p + 1; return p + 1;
case 'U': case 'U':
...@@ -1339,18 +1340,19 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value, ...@@ -1339,18 +1340,19 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value,
if (*value > 0x10ffff if (*value > 0x10ffff
|| (*value >= 0xd800 && *value < 0xe000)) || (*value >= 0xd800 && *value < 0xe000))
{ {
error_at(this->location(), "invalid unicode code point 0x%x", go_error_at(this->location(),
"invalid unicode code point 0x%x",
*value); *value);
// Use the replacement character. // Use the replacement character.
*value = 0xfffd; *value = 0xfffd;
} }
return p + 9; return p + 9;
} }
error_at(this->location(), "invalid big unicode code point"); go_error_at(this->location(), "invalid big unicode code point");
return p + 1; return p + 1;
default: default:
error_at(this->location(), "invalid character after %<\\%>"); go_error_at(this->location(), "invalid character after %<\\%>");
*value = *p; *value = *p;
return p + 1; return p + 1;
} }
...@@ -1382,14 +1384,14 @@ Lex::append_char(unsigned int v, bool is_character, std::string* str, ...@@ -1382,14 +1384,14 @@ Lex::append_char(unsigned int v, bool is_character, std::string* str,
{ {
if (v > 0x10ffff) if (v > 0x10ffff)
{ {
warning_at(location, 0, go_warning_at(location, 0,
"unicode code point 0x%x out of range in string", v); "unicode code point 0x%x out of range in string", v);
// Turn it into the "replacement character". // Turn it into the "replacement character".
v = 0xfffd; v = 0xfffd;
} }
if (v >= 0xd800 && v < 0xe000) if (v >= 0xd800 && v < 0xe000)
{ {
warning_at(location, 0, go_warning_at(location, 0,
"unicode code point 0x%x is invalid surrogate pair", v); "unicode code point 0x%x is invalid surrogate pair", v);
v = 0xfffd; v = 0xfffd;
} }
...@@ -1427,7 +1429,7 @@ Lex::gather_character() ...@@ -1427,7 +1429,7 @@ Lex::gather_character()
if (*p != '\'') if (*p != '\'')
{ {
error_at(this->location(), "unterminated character constant"); go_error_at(this->location(), "unterminated character constant");
this->lineoff_ = p - this->linebuf_; this->lineoff_ = p - this->linebuf_;
return this->make_invalid_token(); return this->make_invalid_token();
} }
...@@ -1461,7 +1463,7 @@ Lex::gather_string() ...@@ -1461,7 +1463,7 @@ Lex::gather_string()
p = this->advance_one_char(p, false, &c, &is_character); p = this->advance_one_char(p, false, &c, &is_character);
if (p >= pend) if (p >= pend)
{ {
error_at(this->location(), "unterminated string"); go_error_at(this->location(), "unterminated string");
--p; --p;
break; break;
} }
...@@ -1505,7 +1507,7 @@ Lex::gather_raw_string() ...@@ -1505,7 +1507,7 @@ Lex::gather_raw_string()
this->lineoff_ = p - this->linebuf_; this->lineoff_ = p - this->linebuf_;
if (!this->require_line()) if (!this->require_line())
{ {
error_at(location, "unterminated raw string"); go_error_at(location, "unterminated raw string");
return Token::make_string_token(value, location); return Token::make_string_token(value, location);
} }
p = this->linebuf_ + this->lineoff_; p = this->linebuf_ + this->lineoff_;
...@@ -1685,7 +1687,7 @@ Lex::skip_c_comment(bool* found_newline) ...@@ -1685,7 +1687,7 @@ Lex::skip_c_comment(bool* found_newline)
{ {
if (!this->require_line()) if (!this->require_line())
{ {
error_at(this->location(), "unterminated comment"); go_error_at(this->location(), "unterminated comment");
return false; return false;
} }
...@@ -1861,7 +1863,7 @@ Lex::skip_cpp_comment() ...@@ -1861,7 +1863,7 @@ Lex::skip_cpp_comment()
} }
} }
if (go_name.empty() || ext_name.empty()) if (go_name.empty() || ext_name.empty())
error_at(loc, "usage: //go:linkname localname linkname"); go_error_at(loc, "usage: //go:linkname localname linkname");
else else
{ {
if (this->linknames_ == NULL) if (this->linknames_ == NULL)
......
...@@ -81,7 +81,8 @@ class Parse ...@@ -81,7 +81,8 @@ class Parse
Expression* expr; Expression* expr;
Type_switch() Type_switch()
: found(false), name(), location(UNKNOWN_LOCATION), expr(NULL) : found(false), name(), location(Linemap::unknown_location()),
expr(NULL)
{ } { }
}; };
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "go-system.h" #include "go-system.h"
#include "go-c.h" #include "go-c.h"
#include "go-diagnostics.h"
#include "types.h" #include "types.h"
#include "expressions.h" #include "expressions.h"
#include "gogo.h" #include "gogo.h"
...@@ -163,7 +164,7 @@ Statement::set_is_error() ...@@ -163,7 +164,7 @@ Statement::set_is_error()
void void
Statement::report_error(const char* msg) Statement::report_error(const char* msg)
{ {
error_at(this->location_, "%s", msg); go_error_at(this->location_, "%s", msg);
this->set_is_error(); this->set_is_error();
} }
...@@ -428,9 +429,9 @@ Temporary_statement::do_check_types(Gogo*) ...@@ -428,9 +429,9 @@ Temporary_statement::do_check_types(Gogo*)
if (!Type::are_assignable(this->type_, this->init_->type(), &reason)) if (!Type::are_assignable(this->type_, this->init_->type(), &reason))
{ {
if (reason.empty()) if (reason.empty())
error_at(this->location(), "incompatible types in assignment"); go_error_at(this->location(), "incompatible types in assignment");
else else
error_at(this->location(), "incompatible types in assignment (%s)", go_error_at(this->location(), "incompatible types in assignment (%s)",
reason.c_str()); reason.c_str());
this->set_is_error(); this->set_is_error();
} }
...@@ -767,9 +768,9 @@ Assignment_statement::do_check_types(Gogo*) ...@@ -767,9 +768,9 @@ Assignment_statement::do_check_types(Gogo*)
if (!Type::are_assignable(lhs_type, rhs_type, &reason)) if (!Type::are_assignable(lhs_type, rhs_type, &reason))
{ {
if (reason.empty()) if (reason.empty())
error_at(this->location(), "incompatible types in assignment"); go_error_at(this->location(), "incompatible types in assignment");
else else
error_at(this->location(), "incompatible types in assignment (%s)", go_error_at(this->location(), "incompatible types in assignment (%s)",
reason.c_str()); reason.c_str());
this->set_is_error(); this->set_is_error();
} }
...@@ -2669,9 +2670,10 @@ Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing, ...@@ -2669,9 +2670,10 @@ Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
else else
{ {
if (reason.empty()) if (reason.empty())
error_at(e->location(), "incompatible type for return value %d", i); go_error_at(e->location(),
"incompatible type for return value %d", i);
else else
error_at(e->location(), go_error_at(e->location(),
"incompatible type for return value %d (%s)", "incompatible type for return value %d (%s)",
i, reason.c_str()); i, reason.c_str());
} }
...@@ -2850,7 +2852,7 @@ Goto_statement::do_check_types(Gogo*) ...@@ -2850,7 +2852,7 @@ Goto_statement::do_check_types(Gogo*)
{ {
if (!this->label_->is_defined()) if (!this->label_->is_defined())
{ {
error_at(this->location(), "reference to undefined label %qs", go_error_at(this->location(), "reference to undefined label %qs",
Gogo::message_name(this->label_->name()).c_str()); Gogo::message_name(this->label_->name()).c_str());
this->set_is_error(); this->set_is_error();
} }
...@@ -3274,7 +3276,7 @@ Case_clauses::Case_clause::check_types(Type* type) ...@@ -3274,7 +3276,7 @@ Case_clauses::Case_clause::check_types(Type* type)
if (!Type::are_assignable(type, (*p)->type(), NULL) if (!Type::are_assignable(type, (*p)->type(), NULL)
&& !Type::are_assignable((*p)->type(), type, NULL)) && !Type::are_assignable((*p)->type(), type, NULL))
{ {
error_at((*p)->location(), go_error_at((*p)->location(),
"type mismatch between switch value and case clause"); "type mismatch between switch value and case clause");
return false; return false;
} }
...@@ -3338,7 +3340,7 @@ Case_clauses::Case_clause::get_backend(Translate_context* context, ...@@ -3338,7 +3340,7 @@ Case_clauses::Case_clause::get_backend(Translate_context* context,
if (!ins.second) if (!ins.second)
{ {
// Value was already present. // Value was already present.
error_at(this->location_, "duplicate case in switch"); go_error_at(this->location_, "duplicate case in switch");
e = Expression::make_error(this->location_); e = Expression::make_error(this->location_);
} }
cases->push_back(e->get_backend(context)); cases->push_back(e->get_backend(context));
...@@ -3722,7 +3724,7 @@ Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing, ...@@ -3722,7 +3724,7 @@ Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
&& !Type::are_compatible_for_comparison(true, this->val_->type(), && !Type::are_compatible_for_comparison(true, this->val_->type(),
Type::make_nil_type(), NULL)) Type::make_nil_type(), NULL))
{ {
error_at(this->val_->location(), go_error_at(this->val_->location(),
"cannot switch on value whose type that may not be compared"); "cannot switch on value whose type that may not be compared");
return Statement::make_error_statement(loc); return Statement::make_error_statement(loc);
} }
...@@ -3857,9 +3859,9 @@ Type_case_clauses::Type_case_clause::lower(Type* switch_val_type, ...@@ -3857,9 +3859,9 @@ Type_case_clauses::Type_case_clause::lower(Type* switch_val_type,
&reason)) &reason))
{ {
if (reason.empty()) if (reason.empty())
error_at(this->location_, "impossible type switch case"); go_error_at(this->location_, "impossible type switch case");
else else
error_at(this->location_, "impossible type switch case (%s)", go_error_at(this->location_, "impossible type switch case (%s)",
reason.c_str()); reason.c_str());
} }
...@@ -4025,7 +4027,7 @@ Type_case_clauses::check_duplicates() const ...@@ -4025,7 +4027,7 @@ Type_case_clauses::check_duplicates() const
t = Type::make_nil_type(); t = Type::make_nil_type();
std::pair<Types_seen::iterator, bool> ins = types_seen.insert(t); std::pair<Types_seen::iterator, bool> ins = types_seen.insert(t);
if (!ins.second) if (!ins.second)
error_at(p->location(), "duplicate type in switch"); go_error_at(p->location(), "duplicate type in switch");
} }
} }
...@@ -4255,7 +4257,7 @@ Send_statement::do_check_types(Gogo*) ...@@ -4255,7 +4257,7 @@ Send_statement::do_check_types(Gogo*)
Channel_type* channel_type = type->channel_type(); Channel_type* channel_type = type->channel_type();
if (channel_type == NULL) if (channel_type == NULL)
{ {
error_at(this->location(), "left operand of %<<-%> must be channel"); go_error_at(this->location(), "left operand of %<<-%> must be channel");
this->set_is_error(); this->set_is_error();
return; return;
} }
...@@ -4656,14 +4658,14 @@ Select_clauses::Select_clause::check_types() ...@@ -4656,14 +4658,14 @@ Select_clauses::Select_clause::check_types()
Channel_type* ct = this->channel_->type()->channel_type(); Channel_type* ct = this->channel_->type()->channel_type();
if (ct == NULL) if (ct == NULL)
{ {
error_at(this->channel_->location(), "expected channel"); go_error_at(this->channel_->location(), "expected channel");
return; return;
} }
if (this->is_send_ && !ct->may_send()) if (this->is_send_ && !ct->may_send())
error_at(this->location(), "invalid send on receive-only channel"); go_error_at(this->location(), "invalid send on receive-only channel");
else if (!this->is_send_ && !ct->may_receive()) else if (!this->is_send_ && !ct->may_receive())
error_at(this->location(), "invalid receive on send-only channel"); go_error_at(this->location(), "invalid receive on send-only channel");
} }
// Whether this clause may fall through to the statement which follows // Whether this clause may fall through to the statement which follows
......
...@@ -1624,7 +1624,7 @@ class Case_clauses ...@@ -1624,7 +1624,7 @@ class Case_clauses
public: public:
Case_clause() Case_clause()
: cases_(NULL), statements_(NULL), is_default_(false), : cases_(NULL), statements_(NULL), is_default_(false),
is_fallthrough_(false), location_(UNKNOWN_LOCATION) is_fallthrough_(false), location_(Linemap::unknown_location())
{ } { }
Case_clause(Expression_list* cases, bool is_default, Block* statements, Case_clause(Expression_list* cases, bool is_default, Block* statements,
...@@ -1811,7 +1811,7 @@ class Type_case_clauses ...@@ -1811,7 +1811,7 @@ class Type_case_clauses
public: public:
Type_case_clause() Type_case_clause()
: type_(NULL), statements_(NULL), is_default_(false), : type_(NULL), statements_(NULL), is_default_(false),
location_(UNKNOWN_LOCATION) location_(Linemap::unknown_location())
{ } { }
Type_case_clause(Type* type, bool is_fallthrough, bool is_default, Type_case_clause(Type* type, bool is_fallthrough, bool is_default,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment