Warn about packages which are imported but not used.
R=iant
https://golang.org/cl/194163
diff --git a/go/go.cc b/go/go.cc
index ebedf51..a174b7b 100644
--- a/go/go.cc
+++ b/go/go.cc
@@ -93,6 +93,8 @@
fclose(file);
}
+ ::gogo->clear_file_scope();
+
// If the global predeclared names are referenced but not defined,
// define them now.
::gogo->define_global_names();
diff --git a/go/gogo.cc b/go/gogo.cc
index 1febfe8..0d7bb34 100644
--- a/go/gogo.cc
+++ b/go/gogo.cc
@@ -254,6 +254,7 @@
{
Package* package = p->second;
package->set_location(location);
+ package->set_is_imported();
std::string ln = local_name;
bool is_ln_exported = is_local_name_exported;
if (ln.empty())
@@ -289,6 +290,7 @@
imp.register_builtin_types(this);
Package* package = imp.import(this, local_name, is_local_name_exported);
this->imports_.insert(std::make_pair(filename, package));
+ package->set_is_imported();
}
// Return whether we are at the global binding level.
@@ -364,7 +366,11 @@
{
Named_object* ret = this->package_->bindings()->lookup(name);
if (ret != NULL)
- return ret;
+ {
+ if (ret->package() != NULL)
+ ret->package()->set_used();
+ return ret;
+ }
}
// We do not look in the global namespace. If we did, the global
@@ -425,7 +431,11 @@
return this->register_package(real_name, unique_prefix, location);
}
else if (alias_arg == "_")
- return this->register_package(real_name, unique_prefix, location);
+ {
+ Package* ret = this->register_package(real_name, unique_prefix, location);
+ ret->set_uses_sink_alias();
+ return ret;
+ }
else
{
*padd_to_globals = false;
@@ -958,6 +968,23 @@
Gogo::clear_file_scope()
{
this->package_->bindings()->clear_file_scope();
+
+ // Warn about packages which were imported but not used.
+ for (Packages::iterator p = this->packages_.begin();
+ p != this->packages_.end();
+ ++p)
+ {
+ Package* package = p->second;
+ if (package != this->package_
+ && package->is_imported()
+ && !package->used()
+ && !package->uses_sink_alias())
+ error_at(package->location(), "imported and not used: %s",
+ package->name().c_str());
+ package->clear_is_imported();
+ package->clear_uses_sink_alias();
+ package->clear_used();
+ }
}
// Traverse the tree.
@@ -3735,7 +3762,7 @@
Package::Package(const std::string& name, const std::string& unique_prefix,
source_location location)
: name_(name), unique_prefix_(unique_prefix), bindings_(new Bindings(NULL)),
- priority_(0), location_(location)
+ priority_(0), location_(location), used_(false), is_imported_(false)
{
gcc_assert(!name.empty() && !unique_prefix.empty());
}
diff --git a/go/gogo.h b/go/gogo.h
index 703f7a7..6cbb6f2 100644
--- a/go/gogo.h
+++ b/go/gogo.h
@@ -2191,6 +2191,51 @@
bindings()
{ return this->bindings_; }
+ // Whether some symbol from the package was used.
+ bool
+ used() const
+ { return this->used_; }
+
+ // Note that some symbol from this package was used.
+ void
+ set_used() const
+ { this->used_ = true; }
+
+ // Clear the used field for the next file.
+ void
+ clear_used()
+ { this->used_ = false; }
+
+ // Whether this package was imported in the current file.
+ bool
+ is_imported() const
+ { return this->is_imported_; }
+
+ // Note that this package was imported in the current file.
+ void
+ set_is_imported()
+ { this->is_imported_ = true; }
+
+ // Clear the imported field for the next file.
+ void
+ clear_is_imported()
+ { this->is_imported_ = false; }
+
+ // Whether this package was imported with a name of "_".
+ bool
+ uses_sink_alias() const
+ { return this->uses_sink_alias_; }
+
+ // Note that this package was imported with a name of "_".
+ void
+ set_uses_sink_alias()
+ { this->uses_sink_alias_ = true; }
+
+ // Clear the sink alias field for the next file.
+ void
+ clear_uses_sink_alias()
+ { this->uses_sink_alias_ = false; }
+
// Look up a name in the package. Returns NULL if the name is not
// found.
Named_object*
@@ -2246,6 +2291,14 @@
int priority_;
// The location of the import statement.
source_location location_;
+ // True if some name from this package was used. This is mutable
+ // because we can use a package even if we have a const pointer to
+ // it.
+ mutable bool used_;
+ // True if this package was imported in the current file.
+ bool is_imported_;
+ // True if this package was imported with a name of "_".
+ bool uses_sink_alias_;
};
// Return codes for the traversal functions. This is not an enum
diff --git a/go/parse.cc b/go/parse.cc
index d52ee63..43c0345 100644
--- a/go/parse.cc
+++ b/go/parse.cc
@@ -193,6 +193,8 @@
return false;
}
+ package->package_value()->set_used();
+
token = this->advance_token();
if (!token->is_identifier())
{
@@ -2023,6 +2025,7 @@
return Expression::make_error(location);
}
package = named_object->package_value();
+ package->set_used();
id = this->peek_token()->identifier();
is_exported = this->peek_token()->is_identifier_exported();
packed = this->gogo_->pack_hidden_name(id, is_exported);
diff --git a/go/unsafe.cc b/go/unsafe.cc
index d23aeda..be5b7cd 100644
--- a/go/unsafe.cc
+++ b/go/unsafe.cc
@@ -26,6 +26,7 @@
is_local_name_exported,
"libgo_unsafe",
location, &add_to_globals);
+ package->set_is_imported();
Bindings* bindings = package->bindings();
@@ -35,6 +36,7 @@
{
Type* type = Type::make_pointer_type(Type::make_void_type());
no = bindings->add_type("Pointer", package, type, UNKNOWN_LOCATION);
+ no->set_package(package);
}
else
{
diff --git a/libgo/testsuite/gotest b/libgo/testsuite/gotest
index ec35e8d..89afd92 100755
--- a/libgo/testsuite/gotest
+++ b/libgo/testsuite/gotest
@@ -142,20 +142,6 @@
# They all compile; now generate the code to call them.
{
- # package spec
- echo 'package main'
- echo
- echo 'import "./_gotest_"'
- if $havex; then
- echo 'import "./_xtest_"'
- fi
- if test "$package" != "testing"; then
- echo 'import "testing"'
- fi
- # test array
- echo
- echo 'var tests = []testing.Test {'
-
# test functions are named TestFoo
# the grep -v eliminates methods and other special names
# that have multiple dots.
@@ -163,12 +149,29 @@
tests=$(nm -s _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/')
if [ "x$tests" = x ]; then
echo 'gotest: warning: no tests matching '$pattern in _gotest_.o $xofile 1>&2
- else
- for i in $tests
- do
- echo ' testing.Test{ "'$i'", '$i' },'
- done
+ exit 2
fi
+
+ # package spec
+ echo 'package main'
+ echo
+ # imports
+ if echo "$tests" | egrep -v '_test\.' >/dev/null; then
+ echo 'import "./_gotest_"'
+ fi
+ if $havex; then
+ echo 'import "./_xtest_"'
+ fi
+ if [ $package != "testing" ]; then
+ echo 'import "testing"'
+ fi
+ # test array
+ echo
+ echo 'var tests = []testing.Test {'
+ for i in $tests
+ do
+ echo ' testing.Test{ "'$i'", '$i' },'
+ done
echo '}'
# body
echo