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>
PR go/77701
......
......@@ -54,8 +54,10 @@ GO_OBJS = \
go/export.o \
go/expressions.o \
go/go-backend.o \
go/go-diagnostics.o \
go/go-dump.o \
go/go-gcc.o \
go/go-gcc-diagnostics.o \
go/go-lang.o \
go/go-linemap.o \
go/go-optimize.o \
......@@ -227,6 +229,7 @@ GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend
CFLAGS-go/go-gcc.o += $(GOINCLUDES)
CFLAGS-go/go-linemap.o += $(GOINCLUDES)
CFLAGS-go/go-sha1.o += $(GOINCLUDES)
CFLAGS-go/go-gcc-diagnostics.o += $(GOINCLUDES)
go/%.o: go/gofrontend/%.cc
$(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
gcc_location() const
{ 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:
source_location gcc_loc_;
};
......@@ -42,4 +38,10 @@ operator<(Location loca, Location locb)
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)
......@@ -30,6 +30,7 @@
#include <map>
#include <set>
#include <vector>
#include <sstream>
#if defined(HAVE_UNORDERED_MAP)
......
4f84c5e0210e674163f3f6462da6f5be9e5b0a36
57bf3f21005c4508003f65207282c057e3526ec0
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
......@@ -16,6 +16,7 @@
#include "ast-dump.h"
#include "go-c.h"
#include "go-dump.h"
#include "go-diagnostics.h"
// The -fgo-dump-ast flag to activate AST dumps.
......@@ -173,7 +174,8 @@ Ast_dump_context::dump(Gogo* gogo, const char* basename)
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;
}
......
......@@ -55,7 +55,7 @@ class Backend
Location location;
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,
......
// 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 @@
#include "go-system.h"
#include "go-c.h"
#include "go-diagnostics.h"
#include "lex.h"
#include "parse.h"
......@@ -68,8 +69,8 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
{
file = fopen(filename, "r");
if (file == NULL)
fatal_error(Linemap::unknown_location(),
"cannot open %s: %m", filename);
go_fatal_error(Linemap::unknown_location(),
"cannot open %s: %m", filename);
}
Lex lexer(filename, file, ::gogo->linemap());
......@@ -88,9 +89,9 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
for (Lex::Linknames::const_iterator p = linknames->begin();
p != linknames->end();
++p)
error_at(p->second.loc,
("//go:linkname only allowed in Go files that "
"import \"unsafe\""));
go_error_at(p->second.loc,
("//go:linkname only allowed in Go files that "
"import \"unsafe\""));
}
all_linknames.insert(linknames->begin(), linknames->end());
}
......
......@@ -6,6 +6,7 @@
#include "go-system.h"
#include "go-diagnostics.h"
#include "import.h"
#ifndef O_BINARY
......@@ -144,7 +145,7 @@ Archive_file::initialize()
struct stat st;
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;
}
this->filesize_ = st.st_size;
......@@ -153,7 +154,7 @@ Archive_file::initialize()
if (::lseek(this->fd_, 0, SEEK_SET) < 0
|| ::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;
}
this->is_thin_archive_ = memcmp(buf, armagt, sizeof(armagt)) == 0;
......@@ -183,7 +184,7 @@ Archive_file::initialize()
char* rdbuf = new char[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());
delete[] rdbuf;
return false;
......@@ -203,7 +204,7 @@ Archive_file::read(off_t offset, off_t size, char* buf)
if (::lseek(this->fd_, offset, SEEK_SET) < 0
|| ::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 true;
......@@ -219,20 +220,20 @@ Archive_file::read_header(off_t off, std::string* pname, off_t* size,
Archive_header hdr;
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;
}
ssize_t got = ::read(this->fd_, &hdr, sizeof hdr);
if (got != sizeof hdr)
{
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)
error_at(this->location_, "%s: short archive header at %ld",
this->filename_.c_str(), static_cast<long>(off));
go_error_at(this->location_, "%s: short archive header at %ld",
this->filename_.c_str(), static_cast<long>(off));
else
error_at(this->location_, "%s: unexpected EOF at %ld",
this->filename_.c_str(), static_cast<long>(off));
go_error_at(this->location_, "%s: unexpected EOF at %ld",
this->filename_.c_str(), static_cast<long>(off));
}
off_t local_nested_off;
if (!this->interpret_header(&hdr, off, pname, size, &local_nested_off))
......@@ -252,8 +253,8 @@ Archive_file::interpret_header(const Archive_header* hdr, off_t off,
{
if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
{
error_at(this->location_, "%s: malformed archive header at %lu",
this->filename_.c_str(), static_cast<unsigned long>(off));
go_error_at(this->location_, "%s: malformed archive header at %lu",
this->filename_.c_str(), static_cast<unsigned long>(off));
return false;
}
......@@ -272,8 +273,8 @@ Archive_file::interpret_header(const Archive_header* hdr, off_t off,
|| *size < 0
|| (*size == LONG_MAX && errno == ERANGE))
{
error_at(this->location_, "%s: malformed archive header size at %lu",
this->filename_.c_str(), static_cast<unsigned long>(off));
go_error_at(this->location_, "%s: malformed archive header size at %lu",
this->filename_.c_str(), static_cast<unsigned long>(off));
return false;
}
......@@ -284,8 +285,9 @@ Archive_file::interpret_header(const Archive_header* hdr, off_t off,
if (name_end == NULL
|| name_end - hdr->ar_name >= static_cast<int>(sizeof hdr->ar_name))
{
error_at(this->location_, "%s: malformed archive header name at %lu",
this->filename_.c_str(), static_cast<unsigned long>(off));
go_error_at(this->location_,
"%s: malformed archive header name at %lu",
this->filename_.c_str(), static_cast<unsigned long>(off));
return false;
}
pname->assign(hdr->ar_name, name_end - hdr->ar_name);
......@@ -321,8 +323,8 @@ Archive_file::interpret_header(const Archive_header* hdr, off_t off,
|| (x == LONG_MAX && errno == ERANGE)
|| static_cast<size_t>(x) >= this->extended_names_.size())
{
error_at(this->location_, "%s: bad extended name index at %lu",
this->filename_.c_str(), static_cast<unsigned long>(off));
go_error_at(this->location_, "%s: bad extended name index at %lu",
this->filename_.c_str(), static_cast<unsigned long>(off));
return false;
}
......@@ -331,8 +333,9 @@ Archive_file::interpret_header(const Archive_header* hdr, off_t off,
if (static_cast<size_t>(name_end - name) > this->extended_names_.size()
|| name_end[-1] != '/')
{
error_at(this->location_, "%s: bad extended name entry at header %lu",
this->filename_.c_str(), static_cast<unsigned long>(off));
go_error_at(this->location_,
"%s: bad extended name entry at header %lu",
this->filename_.c_str(), static_cast<unsigned long>(off));
return false;
}
pname->assign(name, name_end - 1 - name);
......@@ -380,8 +383,8 @@ Archive_file::get_file_and_offset(off_t off, const std::string& hdrname,
int nfd = open(filename.c_str(), O_RDONLY | O_BINARY);
if (nfd < 0)
{
error_at(this->location_, "%s: can't open nested archive %s",
this->filename_.c_str(), filename.c_str());
go_error_at(this->location_, "%s: can't open nested archive %s",
this->filename_.c_str(), filename.c_str());
return false;
}
nfile = new Archive_file(filename, nfd, this->location_);
......@@ -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);
if (*memfd < 0)
{
error_at(this->location_, "%s: %m", filename.c_str());
go_error_at(this->location_, "%s: %m", filename.c_str());
return false;
}
*memoff = 0;
......@@ -499,10 +502,10 @@ Archive_iterator::read_next_header()
{
if (filesize != this->off_)
{
error_at(this->afile_->location(),
"%s: short archive header at %lu",
this->afile_->filename().c_str(),
static_cast<unsigned long>(this->off_));
go_error_at(this->afile_->location(),
"%s: short archive header at %lu",
this->afile_->filename().c_str(),
static_cast<unsigned long>(this->off_));
this->off_ = filesize;
}
this->header_.off = filesize;
......
......@@ -9,6 +9,7 @@
#include "filenames.h"
#include "go-c.h"
#include "go-diagnostics.h"
#include "gogo.h"
#include "lex.h"
#include "types.h"
......@@ -132,7 +133,7 @@ Import::try_package_in_directory(const std::string& filename,
if (fd < 0)
{
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);
if (fd < 0)
......@@ -146,8 +147,8 @@ Import::try_package_in_directory(const std::string& filename,
close(fd);
error_at(location, "%s exists but does not contain any Go export data",
found_filename.c_str());
go_error_at(location, "%s exists but does not contain any Go export data",
found_filename.c_str());
return NULL;
}
......@@ -211,7 +212,7 @@ Import::find_export_data(const std::string& filename, int fd, Location location)
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;
}
......@@ -247,10 +248,10 @@ Import::find_object_export_data(const std::string& filename,
if (errmsg != NULL)
{
if (err == 0)
error_at(location, "%s: %s", filename.c_str(), errmsg);
go_error_at(location, "%s: %s", filename.c_str(), errmsg);
else
error_at(location, "%s: %s: %s", filename.c_str(), errmsg,
xstrerror(err));
go_error_at(location, "%s: %s: %s", filename.c_str(), errmsg,
xstrerror(err));
return NULL;
}
......@@ -307,9 +308,9 @@ Import::import(Gogo* gogo, const std::string& local_name,
}
else
{
error_at(this->location_,
("error in import data at %d: invalid magic string"),
stream->pos());
go_error_at(this->location_,
("error in import data at %d: invalid magic string"),
stream->pos());
return NULL;
}
......@@ -382,11 +383,11 @@ Import::import(Gogo* gogo, const std::string& local_name,
break;
else
{
error_at(this->location_,
("error in import data at %d: "
"expected %<const%>, %<type%>, %<var%>, "
"%<func%>, or %<checksum%>"),
stream->pos());
go_error_at(this->location_,
("error in import data at %d: "
"expected %<const%>, %<type%>, %<var%>, "
"%<func%>, or %<checksum%>"),
stream->pos());
stream->set_saw_error();
return NULL;
}
......@@ -664,9 +665,9 @@ Import::read_type()
: (static_cast<size_t>(index) >= this->types_.size()
|| this->types_[index] == NULL))
{
error_at(this->location_,
"error in import data at %d: bad type index %d",
stream->pos(), index);
go_error_at(this->location_,
"error in import data at %d: bad type index %d",
stream->pos(), index);
stream->set_saw_error();
return Type::make_error_type();
}
......@@ -677,9 +678,9 @@ Import::read_type()
if (c != ' ')
{
if (!stream->saw_error())
error_at(this->location_,
"error in import data at %d: expect %< %> or %<>%>'",
stream->pos());
go_error_at(this->location_,
"error in import data at %d: expect %< %> or %<>%>'",
stream->pos());
stream->set_saw_error();
stream->advance(1);
return Type::make_error_type();
......@@ -689,9 +690,9 @@ Import::read_type()
|| (static_cast<size_t>(index) < this->types_.size()
&& this->types_[index] != NULL))
{
error_at(this->location_,
"error in import data at %d: type index already defined",
stream->pos());
go_error_at(this->location_,
"error in import data at %d: type index already defined",
stream->pos());
stream->set_saw_error();
return Type::make_error_type();
}
......@@ -768,8 +769,8 @@ Import::read_type()
no = package->add_type_declaration(type_name, this->location_);
else if (!no->is_type_declaration() && !no->is_type())
{
error_at(this->location_, "imported %<%s.%s%> both type and non-type",
pkgpath.c_str(), Gogo::message_name(type_name).c_str());
go_error_at(this->location_, "imported %<%s.%s%> both type and non-type",
pkgpath.c_str(), Gogo::message_name(type_name).c_str());
stream->set_saw_error();
return Type::make_error_type();
}
......@@ -866,9 +867,10 @@ Import::read_escape()
if (c != '>')
{
error_at(this->location(),
"error in import data at %d: expect %< %> or %<>%>, got %c",
stream->pos(), c);
go_error_at(this->location(),
("error in import data at %d: "
"expect %< %> or %<>%>, got %c"),
stream->pos(), c);
stream->set_saw_error();
stream->advance(1);
escape = Escape_note::make_tag(Node::ESCAPE_UNKNOWN);
......@@ -961,8 +963,8 @@ Import::string_to_int(const std::string &s, bool is_neg_ok, int* ret)
long prio = strtol(s.c_str(), &end, 10);
if (*end != '\0' || prio > 0x7fffffff || (prio < 0 && !is_neg_ok))
{
error_at(this->location_, "invalid integer in import data at %d",
this->stream_->pos());
go_error_at(this->location_, "invalid integer in import data at %d",
this->stream_->pos());
this->stream_->set_saw_error();
return false;
}
......@@ -1018,8 +1020,8 @@ Import::Stream::require_bytes(Location location, const char* bytes,
|| memcmp(bytes, read, length) != 0)
{
if (!this->saw_error_)
error_at(location, "import error at %d: expected %<%.*s%>",
this->pos(), static_cast<int>(length), bytes);
go_error_at(location, "import error at %d: expected %<%.*s%>",
this->pos(), static_cast<int>(length), bytes);
this->saw_error_ = true;
return;
}
......@@ -1033,7 +1035,7 @@ Stream_from_file::Stream_from_file(int fd)
{
if (lseek(fd, 0, SEEK_SET) != 0)
{
error("lseek failed: %m");
go_fatal_error(Linemap::unknown_location(), "lseek failed: %m");
this->set_saw_error();
}
}
......@@ -1061,7 +1063,7 @@ Stream_from_file::do_peek(size_t length, const char** bytes)
if (got < 0)
{
if (!this->saw_error())
error("read failed: %m");
go_fatal_error(Linemap::unknown_location(), "read failed: %m");
this->set_saw_error();
return false;
}
......@@ -1069,7 +1071,7 @@ Stream_from_file::do_peek(size_t length, const char** bytes)
if (lseek(this->fd_, - got, SEEK_CUR) != 0)
{
if (!this->saw_error())
error("lseek failed: %m");
go_fatal_error(Linemap::unknown_location(), "lseek failed: %m");
this->set_saw_error();
return false;
}
......@@ -1091,7 +1093,7 @@ Stream_from_file::do_advance(size_t skip)
if (lseek(this->fd_, skip, SEEK_CUR) != 0)
{
if (!this->saw_error())
error("lseek failed: %m");
go_fatal_error(Linemap::unknown_location(), "lseek failed: %m");
this->set_saw_error();
}
if (!this->data_.empty())
......
......@@ -5,6 +5,7 @@
// license that can be found in the LICENSE file.
#include "go-system.h"
#include "go-diagnostics.h"
#include "lex.h"
......@@ -477,7 +478,7 @@ Lex::get_line()
{
size_t ns = 2 * size + 1;
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];
memcpy(nb, buf, cur);
delete[] buf;
......@@ -743,9 +744,9 @@ Lex::next_token()
return this->gather_identifier();
if (!issued_error)
error_at(this->location(),
"invalid character 0x%x in input file",
ci);
go_error_at(this->location(),
"invalid character 0x%x in input file",
ci);
p = pend;
......@@ -834,7 +835,7 @@ Lex::advance_one_utf8_char(const char* p, unsigned int* value,
if (*p == '\0')
{
error_at(this->location(), "invalid NUL byte");
go_error_at(this->location(), "invalid NUL byte");
*issued_error = true;
*value = 0;
return p + 1;
......@@ -843,7 +844,7 @@ Lex::advance_one_utf8_char(const char* p, unsigned int* value,
int adv = Lex::fetch_char(p, value);
if (adv == 0)
{
error_at(this->location(), "invalid UTF-8 encoding");
go_error_at(this->location(), "invalid UTF-8 encoding");
*issued_error = true;
return p + 1;
}
......@@ -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.
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;
}
......@@ -890,9 +891,9 @@ Lex::gather_identifier()
break;
this->lineoff_ = p - this->linebuf_;
error_at(this->location(),
"invalid character 0x%x in identifier",
cc);
go_error_at(this->location(),
"invalid character 0x%x in identifier",
cc);
if (!has_non_ascii_char)
{
buf.assign(pstart, p - pstart);
......@@ -925,9 +926,9 @@ Lex::gather_identifier()
// handling behavior if we swallow this character after
// giving an error.
if (!issued_error)
error_at(this->location(),
"invalid character 0x%x in identifier",
ci);
go_error_at(this->location(),
"invalid character 0x%x in identifier",
ci);
is_invalid = true;
}
if (is_first)
......@@ -1109,9 +1110,9 @@ Lex::gather_number()
if (r != 0)
{
if (base == 8)
error_at(this->location(), "invalid octal literal");
go_error_at(this->location(), "invalid octal literal");
else
error_at(this->location(), "invalid hex literal");
go_error_at(this->location(), "invalid hex literal");
}
if (neg)
......@@ -1225,7 +1226,7 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value,
if (is_single_quote
&& (*value == '\'' || *value == '\n')
&& !issued_error)
error_at(this->location(), "invalid character literal");
go_error_at(this->location(), "invalid character literal");
return ret;
}
else
......@@ -1244,12 +1245,12 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value,
+ Lex::octal_value(p[2]));
if (*value > 255)
{
error_at(this->location(), "invalid octal constant");
go_error_at(this->location(), "invalid octal constant");
*value = 255;
}
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'
? p + 2
: p + 1);
......@@ -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]);
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])
? p + 2
: p + 1);
......@@ -1292,12 +1293,12 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value,
return p + 1;
case '\'':
if (!is_single_quote)
error_at(this->location(), "invalid quoted character");
go_error_at(this->location(), "invalid quoted character");
*value = '\'';
return p + 1;
case '"':
if (is_single_quote)
error_at(this->location(), "invalid quoted character");
go_error_at(this->location(), "invalid quoted character");
*value = '"';
return p + 1;
......@@ -1311,15 +1312,15 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value,
+ Lex::hex_val(p[4]));
if (*value >= 0xd800 && *value < 0xe000)
{
error_at(this->location(),
"invalid unicode code point 0x%x",
*value);
go_error_at(this->location(),
"invalid unicode code point 0x%x",
*value);
// Use the replacement character.
*value = 0xfffd;
}
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;
case 'U':
......@@ -1339,18 +1340,19 @@ Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value,
if (*value > 0x10ffff
|| (*value >= 0xd800 && *value < 0xe000))
{
error_at(this->location(), "invalid unicode code point 0x%x",
*value);
go_error_at(this->location(),
"invalid unicode code point 0x%x",
*value);
// Use the replacement character.
*value = 0xfffd;
}
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;
default:
error_at(this->location(), "invalid character after %<\\%>");
go_error_at(this->location(), "invalid character after %<\\%>");
*value = *p;
return p + 1;
}
......@@ -1382,15 +1384,15 @@ Lex::append_char(unsigned int v, bool is_character, std::string* str,
{
if (v > 0x10ffff)
{
warning_at(location, 0,
"unicode code point 0x%x out of range in string", v);
go_warning_at(location, 0,
"unicode code point 0x%x out of range in string", v);
// Turn it into the "replacement character".
v = 0xfffd;
}
if (v >= 0xd800 && v < 0xe000)
{
warning_at(location, 0,
"unicode code point 0x%x is invalid surrogate pair", v);
go_warning_at(location, 0,
"unicode code point 0x%x is invalid surrogate pair", v);
v = 0xfffd;
}
if (v <= 0xffff)
......@@ -1427,7 +1429,7 @@ Lex::gather_character()
if (*p != '\'')
{
error_at(this->location(), "unterminated character constant");
go_error_at(this->location(), "unterminated character constant");
this->lineoff_ = p - this->linebuf_;
return this->make_invalid_token();
}
......@@ -1461,7 +1463,7 @@ Lex::gather_string()
p = this->advance_one_char(p, false, &c, &is_character);
if (p >= pend)
{
error_at(this->location(), "unterminated string");
go_error_at(this->location(), "unterminated string");
--p;
break;
}
......@@ -1505,7 +1507,7 @@ Lex::gather_raw_string()
this->lineoff_ = p - this->linebuf_;
if (!this->require_line())
{
error_at(location, "unterminated raw string");
go_error_at(location, "unterminated raw string");
return Token::make_string_token(value, location);
}
p = this->linebuf_ + this->lineoff_;
......@@ -1685,7 +1687,7 @@ Lex::skip_c_comment(bool* found_newline)
{
if (!this->require_line())
{
error_at(this->location(), "unterminated comment");
go_error_at(this->location(), "unterminated comment");
return false;
}
......@@ -1861,7 +1863,7 @@ Lex::skip_cpp_comment()
}
}
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
{
if (this->linknames_ == NULL)
......
......@@ -81,7 +81,8 @@ class Parse
Expression* expr;
Type_switch()
: found(false), name(), location(UNKNOWN_LOCATION), expr(NULL)
: found(false), name(), location(Linemap::unknown_location()),
expr(NULL)
{ }
};
......
......@@ -7,6 +7,7 @@
#include "go-system.h"
#include "go-c.h"
#include "go-diagnostics.h"
#include "types.h"
#include "expressions.h"
#include "gogo.h"
......@@ -163,7 +164,7 @@ Statement::set_is_error()
void
Statement::report_error(const char* msg)
{
error_at(this->location_, "%s", msg);
go_error_at(this->location_, "%s", msg);
this->set_is_error();
}
......@@ -428,9 +429,9 @@ Temporary_statement::do_check_types(Gogo*)
if (!Type::are_assignable(this->type_, this->init_->type(), &reason))
{
if (reason.empty())
error_at(this->location(), "incompatible types in assignment");
go_error_at(this->location(), "incompatible types in assignment");
else
error_at(this->location(), "incompatible types in assignment (%s)",
go_error_at(this->location(), "incompatible types in assignment (%s)",
reason.c_str());
this->set_is_error();
}
......@@ -767,10 +768,10 @@ Assignment_statement::do_check_types(Gogo*)
if (!Type::are_assignable(lhs_type, rhs_type, &reason))
{
if (reason.empty())
error_at(this->location(), "incompatible types in assignment");
go_error_at(this->location(), "incompatible types in assignment");
else
error_at(this->location(), "incompatible types in assignment (%s)",
reason.c_str());
go_error_at(this->location(), "incompatible types in assignment (%s)",
reason.c_str());
this->set_is_error();
}
......@@ -2669,11 +2670,12 @@ Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
else
{
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
error_at(e->location(),
"incompatible type for return value %d (%s)",
i, reason.c_str());
go_error_at(e->location(),
"incompatible type for return value %d (%s)",
i, reason.c_str());
}
}
go_assert(lhs->size() == rhs->size());
......@@ -2850,8 +2852,8 @@ Goto_statement::do_check_types(Gogo*)
{
if (!this->label_->is_defined())
{
error_at(this->location(), "reference to undefined label %qs",
Gogo::message_name(this->label_->name()).c_str());
go_error_at(this->location(), "reference to undefined label %qs",
Gogo::message_name(this->label_->name()).c_str());
this->set_is_error();
}
}
......@@ -3274,8 +3276,8 @@ Case_clauses::Case_clause::check_types(Type* type)
if (!Type::are_assignable(type, (*p)->type(), NULL)
&& !Type::are_assignable((*p)->type(), type, NULL))
{
error_at((*p)->location(),
"type mismatch between switch value and case clause");
go_error_at((*p)->location(),
"type mismatch between switch value and case clause");
return false;
}
}
......@@ -3338,7 +3340,7 @@ Case_clauses::Case_clause::get_backend(Translate_context* context,
if (!ins.second)
{
// 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_);
}
cases->push_back(e->get_backend(context));
......@@ -3722,8 +3724,8 @@ Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
&& !Type::are_compatible_for_comparison(true, this->val_->type(),
Type::make_nil_type(), NULL))
{
error_at(this->val_->location(),
"cannot switch on value whose type that may not be compared");
go_error_at(this->val_->location(),
"cannot switch on value whose type that may not be compared");
return Statement::make_error_statement(loc);
}
......@@ -3857,10 +3859,10 @@ Type_case_clauses::Type_case_clause::lower(Type* switch_val_type,
&reason))
{
if (reason.empty())
error_at(this->location_, "impossible type switch case");
go_error_at(this->location_, "impossible type switch case");
else
error_at(this->location_, "impossible type switch case (%s)",
reason.c_str());
go_error_at(this->location_, "impossible type switch case (%s)",
reason.c_str());
}
Expression* ref = Expression::make_temporary_reference(descriptor_temp,
......@@ -4025,7 +4027,7 @@ Type_case_clauses::check_duplicates() const
t = Type::make_nil_type();
std::pair<Types_seen::iterator, bool> ins = types_seen.insert(t);
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*)
Channel_type* channel_type = type->channel_type();
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();
return;
}
......@@ -4656,14 +4658,14 @@ Select_clauses::Select_clause::check_types()
Channel_type* ct = this->channel_->type()->channel_type();
if (ct == NULL)
{
error_at(this->channel_->location(), "expected channel");
go_error_at(this->channel_->location(), "expected channel");
return;
}
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())
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
......
......@@ -1624,7 +1624,7 @@ class Case_clauses
public:
Case_clause()
: 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,
......@@ -1811,7 +1811,7 @@ class Type_case_clauses
public:
Type_case_clause()
: 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,
......
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