diff options
Diffstat (limited to 'gcc/go/gofrontend/go-diagnostics.cc')
-rw-r--r-- | gcc/go/gofrontend/go-diagnostics.cc | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/gcc/go/gofrontend/go-diagnostics.cc b/gcc/go/gofrontend/go-diagnostics.cc new file mode 100644 index 00000000000..21e45b3af37 --- /dev/null +++ b/gcc/go/gofrontend/go-diagnostics.cc @@ -0,0 +1,177 @@ +// 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); +} |