compiler: allow //go:embed in files underscore-importing embed

The embed spec allows for //go:embed to be used in files that
underscore-import package "embed". This is useful for embeds to
[]byte and string vars because the embed.FS type may not be referenced
if those are the only types of embeds in a file. Because the compiler
previously checked whether there were any aliases to the embed
package to decide if //go:embed could be used, it would reject
files with only underscore imports of embed. Instead, record
whether the embed import is encountered at all, similar to what
is done with unsafe, to decide whether //go:embed is allowed.

Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/297553
This commit is contained in:
Michael Matloob 2021-03-01 19:02:38 -05:00 committed by Ian Lance Taylor
parent df003d1e0b
commit d1776b7757
5 changed files with 14 additions and 21 deletions

View File

@ -1,4 +1,4 @@
56cf388da8d04bbd3824c4df34d77a8afa69749b
2c5188b5ad6143e791f2ba42f02a4ea7887d87b6
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.

View File

@ -663,21 +663,6 @@ Embedcfg_reader::error(const char* msg)
this->filename_, msg);
}
// Return whether the current file imports "embed".
bool
Gogo::is_embed_imported() const
{
Packages::const_iterator p = this->packages_.find("embed");
if (p == this->packages_.end())
return false;
// We track current file imports in the package aliases, where a
// typical import will just list the package name in aliases. So
// the package has been imported if there is at least one alias.
return !p->second->aliases().empty();
}
// Implement the sort order for a list of embedded files, as discussed
// at the docs for embed.FS.

View File

@ -37,6 +37,7 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
imports_(),
imported_unsafe_(false),
current_file_imported_unsafe_(false),
current_file_imported_embed_(false),
packages_(),
init_functions_(),
var_deps_(),
@ -469,6 +470,9 @@ Gogo::import_package(const std::string& filename,
return;
}
if (filename == "embed")
this->current_file_imported_embed_ = true;
Imports::const_iterator p = this->imports_.find(filename);
if (p != this->imports_.end())
{
@ -2717,6 +2721,7 @@ Gogo::clear_file_scope()
}
this->current_file_imported_unsafe_ = false;
this->current_file_imported_embed_ = false;
}
// Queue up a type-specific hash function for later writing. These

View File

@ -397,10 +397,6 @@ class Gogo
void
read_embedcfg(const char* filename);
// Return whether the current file imports "embed".
bool
is_embed_imported() const;
// Build an initializer for a variable with a go:embed directive.
Expression*
initializer_for_embeds(Type*, const std::vector<std::string>*, Location);
@ -709,6 +705,11 @@ class Gogo
current_file_imported_unsafe() const
{ return this->current_file_imported_unsafe_; }
// Return whether the current file imported the embed package.
bool
current_file_imported_embed() const
{ return this->current_file_imported_embed_; }
// Clear out all names in file scope. This is called when we start
// parsing a new file.
void
@ -1251,6 +1252,8 @@ class Gogo
bool imported_unsafe_;
// Whether the magic unsafe package was imported by the current file.
bool current_file_imported_unsafe_;
// Whether the embed package was imported by the current file.
bool current_file_imported_embed_;
// Mapping from package names we have seen to packages. This does
// not include the package we are compiling.
Packages packages_;

View File

@ -1321,7 +1321,7 @@ Parse::declaration()
embeds = new(std::vector<std::string>);
this->lex_->get_and_clear_embeds(embeds);
if (!this->gogo_->is_embed_imported())
if (!this->gogo_->current_file_imported_embed())
{
go_error_at(token->location(),
"invalid go:embed: missing import %<embed%>");