1 // embed.cc -- Go frontend go:embed handling.
2 
3 // Copyright 2021 The Go Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file.
6 
7 #include "go-system.h"
8 
9 #include "operator.h"
10 #include "go-diagnostics.h"
11 #include "lex.h"
12 #include "types.h"
13 #include "expressions.h"
14 #include "gogo.h"
15 
16 #ifndef O_BINARY
17 #define O_BINARY 0
18 #endif
19 
20 // Read a file into *DATA.  Returns false on error.
21 
22 static bool
read_file(const char * filename,Location loc,std::string * data)23 read_file(const char* filename, Location loc, std::string* data)
24 {
25   int fd = open(filename, O_RDONLY | O_BINARY);
26   if (fd < 0)
27     {
28       go_error_at(loc, "%s: %m", filename);
29       return false;
30     }
31 
32   struct stat st;
33   if (fstat(fd, &st) < 0)
34     {
35       go_error_at(loc, "%s: %m", filename);
36       return false;
37     }
38   off_t want = st.st_size;
39 
40   // Most files read here are going to be incorporated into the object file
41   // and then the executable.  Set a limit on the size we will accept.
42   if (want > 2000000000)
43     {
44       go_error_at(loc, "%s: file too large", filename);
45       return false;
46     }
47 
48   data->resize(want);
49   off_t got = 0;
50   while (want > 0)
51     {
52       // C++11 requires that std::string use contiguous bytes, so this
53       // is safe.
54       ssize_t n = read(fd, &(*data)[got], want);
55       if (n < 0)
56 	{
57 	  close(fd);
58 	  go_error_at(loc, "%s: %m", filename);
59 	  return false;
60 	}
61       if (n == 0)
62 	{
63 	  data->resize(got);
64 	  break;
65 	}
66       got += n;
67       want -= n;
68     }
69 
70   close(fd);
71   return true;
72 }
73 
74 // A JSON value as read from an embedcfg file.  For our purposes a
75 // JSON value is a string, or a list of strings, or a mapping from
76 // strings to values.  We don't expect any numbers.  We also don't
77 // expect an array of anything other than strings; that is, we don't
78 // accept an array of general JSON values.
79 
80 class Json_value
81 {
82  public:
83   // The types of values.
84   enum Json_value_classification
85     {
86       JSON_VALUE_UNKNOWN,
87       JSON_VALUE_STRING,
88       JSON_VALUE_ARRAY,
89       JSON_VALUE_MAP
90     };
91 
Json_value()92   Json_value()
93     : classification_(JSON_VALUE_UNKNOWN), string_(), array_(), map_()
94   { }
95 
96   ~Json_value();
97 
98   Json_value_classification
classification() const99   classification() const
100   { return this->classification_; }
101 
102   // Set to a string value.
103   void
set_string(const std::string & str)104   set_string(const std::string& str)
105   {
106     go_assert(this->classification_ == JSON_VALUE_UNKNOWN);
107     this->classification_ = JSON_VALUE_STRING;
108     this->string_ = str;
109   }
110 
111   // Start an array value.
112   void
start_array()113   start_array()
114   {
115     go_assert(this->classification_ == JSON_VALUE_UNKNOWN);
116     this->classification_ = JSON_VALUE_ARRAY;
117   }
118 
119   // Add an array entry.
120   void
add_array_entry(const std::string & s)121   add_array_entry(const std::string& s)
122   {
123     go_assert(this->classification_ == JSON_VALUE_ARRAY);
124     this->array_.push_back(s);
125   }
126 
127   // Start a map value.
128   void
start_map()129   start_map()
130   {
131     go_assert(this->classification_ == JSON_VALUE_UNKNOWN);
132     this->classification_ = JSON_VALUE_MAP;
133   }
134 
135   // Add a map entry.
136   void
add_map_entry(const std::string & key,Json_value * val)137   add_map_entry(const std::string& key, Json_value* val)
138   {
139     go_assert(this->classification_ == JSON_VALUE_MAP);
140     this->map_[key] = val;
141   }
142 
143   // Return the strings from a string value.
144   const std::string&
to_string() const145   to_string() const
146   {
147     go_assert(this->classification_ == JSON_VALUE_STRING);
148     return this->string_;
149   }
150 
151   // Fetch a vector of strings, and drop them from the JSON value.
152   void
get_and_clear_array(std::vector<std::string> * v)153   get_and_clear_array(std::vector<std::string>* v)
154   {
155     go_assert(this->classification_ == JSON_VALUE_ARRAY);
156     std::swap(*v, this->array_);
157   }
158 
159   // Look up a map entry.  Returns NULL if not found.
160   Json_value*
161   lookup_map_entry(const std::string& key);
162 
163   // Iterate over a map.
164   typedef Unordered_map(std::string, Json_value*)::iterator map_iterator;
165 
166   map_iterator
map_begin()167   map_begin()
168   {
169     go_assert(this->classification_ == JSON_VALUE_MAP);
170     return this->map_.begin();
171   }
172 
173   map_iterator
map_end()174   map_end()
175   { return this->map_.end(); }
176 
177  private:
178   // Classification.
179   Json_value_classification classification_;
180   // A string, for JSON_VALUE_STRING.
181   std::string string_;
182   // Array, for JSON_VALUE_ARRAY.
183   std::vector<std::string> array_;
184   // Mapping, for JSON_VALUE_MAP.
185   Unordered_map(std::string, Json_value*) map_;
186 };
187 
188 // Delete a JSON value.
189 
~Json_value()190 Json_value::~Json_value()
191 {
192   if (this->classification_ == JSON_VALUE_MAP)
193     {
194       for (map_iterator p = this->map_begin();
195 	   p != this->map_end();
196 	   ++p)
197 	delete p->second;
198     }
199 }
200 
201 // Look up a map entry in a JSON value.
202 
203 Json_value*
lookup_map_entry(const std::string & key)204 Json_value::lookup_map_entry(const std::string& key)
205 {
206   go_assert(this->classification_ == JSON_VALUE_MAP);
207   Unordered_map(std::string, Json_value*)::iterator p = this->map_.find(key);
208   if (p == this->map_.end())
209     return NULL;
210   return p->second;
211 }
212 
213 // Manage reading the embedcfg file.
214 
215 class Embedcfg_reader
216 {
217  public:
Embedcfg_reader(const char * filename)218   Embedcfg_reader(const char* filename)
219     : filename_(filename), data_(), p_(NULL), pend_(NULL)
220   {}
221 
222   // Read the contents of FILENAME.  Return whether it succeeded.
223   bool
224   initialize_from_file();
225 
226   // Read a JSON object.
227   bool
228   read_object(Json_value*);
229 
230   // Report an error if not at EOF.
231   void
232   check_eof();
233 
234   // Report an error for the embedcfg file.
235   void
236   error(const char* msg);
237 
238  private:
239   bool
240   read_value(Json_value*);
241 
242   bool
243   read_array(Json_value*);
244 
245   bool
246   read_string(std::string*);
247 
248   bool
249   skip_whitespace(bool eof_ok);
250 
251   // File name.
252   const char* filename_;
253   // File contents.
254   std::string data_;
255   // Next character to process.
256   const char *p_;
257   // End of data.
258   const char *pend_;
259 };
260 
261 // Read the embedcfg file.
262 
263 void
read_embedcfg(const char * filename)264 Gogo::read_embedcfg(const char *filename)
265 {
266   class Embedcfg_reader r(filename);
267   if (!r.initialize_from_file())
268     return;
269 
270   Json_value val;
271   if (!r.read_object(&val))
272     return;
273 
274   r.check_eof();
275 
276   if (val.classification() != Json_value::JSON_VALUE_MAP)
277     {
278       r.error("invalid embedcfg: not a JSON object");
279       return;
280     }
281 
282   Json_value* patterns = val.lookup_map_entry("Patterns");
283   if (patterns == NULL)
284     {
285       r.error("invalid embedcfg: missing Patterns");
286       return;
287     }
288   if (patterns->classification() != Json_value::JSON_VALUE_MAP)
289     {
290       r.error("invalid embedcfg: Patterns is not a JSON object");
291       return;
292     }
293 
294   Json_value* files = val.lookup_map_entry("Files");
295   if (files == NULL)
296     {
297       r.error("invalid embedcfg: missing Files");
298       return;
299     }
300   if (files->classification() != Json_value::JSON_VALUE_MAP)
301     {
302       r.error("invalid embedcfg: Files is not a JSON object");
303       return;
304     }
305 
306   for (Json_value::map_iterator p = patterns->map_begin();
307        p != patterns->map_end();
308        ++p)
309     {
310       if (p->second->classification() != Json_value::JSON_VALUE_ARRAY)
311 	{
312 	  r.error("invalid embedcfg: Patterns entry is not an array");
313 	  return;
314 	}
315       std::vector<std::string> files;
316       p->second->get_and_clear_array(&files);
317 
318       std::pair<std::string, std::vector<std::string> > val;
319       val.first = p->first;
320       std::pair<Embed_patterns::iterator, bool> ins =
321 	this->embed_patterns_.insert(val);
322       if (!ins.second)
323 	{
324 	  r.error("invalid embedcfg: duplicate Patterns entry");
325 	  return;
326 	}
327       std::swap(ins.first->second, files);
328     }
329 
330   for (Json_value::map_iterator p = files->map_begin();
331        p != files->map_end();
332        ++p)
333     {
334       if (p->second->classification() != Json_value::JSON_VALUE_STRING)
335 	{
336 	  r.error("invalid embedcfg: Files entry is not a string");
337 	  return;
338 	}
339       this->embed_files_[p->first] = p->second->to_string();
340     }
341 }
342 
343 // Read the contents of FILENAME into this->data_.  Returns whether it
344 // succeeded.
345 
346 bool
initialize_from_file()347 Embedcfg_reader::initialize_from_file()
348 {
349   if (!read_file(this->filename_, Linemap::unknown_location(), &this->data_))
350     return false;
351   if (this->data_.empty())
352     {
353       this->error("empty file");
354       return false;
355     }
356   this->p_ = this->data_.data();
357   this->pend_ = this->p_ + this->data_.size();
358   return true;
359 }
360 
361 // Read a JSON object into VAL.  Return whether it succeeded.
362 
363 bool
read_object(Json_value * val)364 Embedcfg_reader::read_object(Json_value* val)
365 {
366   if (!this->skip_whitespace(false))
367     return false;
368   if (*this->p_ != '{')
369     {
370       this->error("expected %<{%>");
371       return false;
372     }
373   ++this->p_;
374 
375   val->start_map();
376 
377   if (!this->skip_whitespace(false))
378     return false;
379   if (*this->p_ == '}')
380     {
381       ++this->p_;
382       return true;
383     }
384 
385   while (true)
386     {
387       if (!this->skip_whitespace(false))
388 	return false;
389       if (*this->p_ != '"')
390 	{
391 	  this->error("expected %<\"%>");
392 	  return false;
393 	}
394 
395       std::string key;
396       if (!this->read_string(&key))
397 	return false;
398 
399       if (!this->skip_whitespace(false))
400 	return false;
401       if (*this->p_ != ':')
402 	{
403 	  this->error("expected %<:%>");
404 	  return false;
405 	}
406       ++this->p_;
407 
408       Json_value* subval = new Json_value();
409       if (!this->read_value(subval))
410 	return false;
411 
412       val->add_map_entry(key, subval);
413 
414       if (!this->skip_whitespace(false))
415 	return false;
416       if (*this->p_ == '}')
417 	{
418 	  ++this->p_;
419 	  return true;
420 	}
421       if (*this->p_ != ',')
422 	{
423 	  this->error("expected %<,%> or %<}%>");
424 	  return false;
425 	}
426       ++this->p_;
427     }
428 }
429 
430 // Read a JSON array into VAL.  Return whether it succeeded.
431 
432 bool
read_array(Json_value * val)433 Embedcfg_reader::read_array(Json_value* val)
434 {
435   if (!this->skip_whitespace(false))
436     return false;
437   if (*this->p_ != '[')
438     {
439       this->error("expected %<[%>");
440       return false;
441     }
442   ++this->p_;
443 
444   val->start_array();
445 
446   if (!this->skip_whitespace(false))
447     return false;
448   if (*this->p_ == ']')
449     {
450       ++this->p_;
451       return true;
452     }
453 
454   while (true)
455     {
456       // If we were parsing full JSON we would call read_value here,
457       // not read_string.
458 
459       std::string s;
460       if (!this->read_string(&s))
461 	return false;
462 
463       val->add_array_entry(s);
464 
465       if (!this->skip_whitespace(false))
466 	return false;
467       if (*this->p_ == ']')
468 	{
469 	  ++this->p_;
470 	  return true;
471 	}
472       if (*this->p_ != ',')
473 	{
474 	  this->error("expected %<,%> or %<]%>");
475 	  return false;
476 	}
477       ++this->p_;
478     }
479 }
480 
481 // Read a JSON value into VAL.  Return whether it succeeded.
482 
483 bool
read_value(Json_value * val)484 Embedcfg_reader::read_value(Json_value* val)
485 {
486   if (!this->skip_whitespace(false))
487     return false;
488   switch (*this->p_)
489     {
490     case '"':
491       {
492 	std::string s;
493 	if (!this->read_string(&s))
494 	  return false;
495 	val->set_string(s);
496 	return true;
497       }
498 
499     case '{':
500       return this->read_object(val);
501 
502     case '[':
503       return this->read_array(val);
504 
505     default:
506       this->error("invalid JSON syntax");
507       return false;
508     }
509 }
510 
511 // Read a JSON string.  Return whether it succeeded.
512 
513 bool
read_string(std::string * str)514 Embedcfg_reader::read_string(std::string* str)
515 {
516   if (!this->skip_whitespace(false))
517     return false;
518   if (*this->p_ != '"')
519     {
520       this->error("expected %<\"%>");
521       return false;
522     }
523   ++this->p_;
524 
525   str->clear();
526   while (this->p_ < this->pend_ && *this->p_ != '"')
527     {
528       if (*this->p_ != '\\')
529 	{
530 	  str->push_back(*this->p_);
531 	  ++this->p_;
532 	  continue;
533 	}
534 
535       ++this->p_;
536       if (this->p_ >= this->pend_)
537 	{
538 	  this->error("unterminated string");
539 	  return false;
540 	}
541       switch (*this->p_)
542 	{
543 	case '"': case '\\': case '/':
544 	  str->push_back(*this->p_);
545 	  ++this->p_;
546 	  break;
547 
548 	case 'b':
549 	  str->push_back('\b');
550 	  ++this->p_;
551 	  break;
552 
553 	case 'f':
554 	  str->push_back('\f');
555 	  ++this->p_;
556 	  break;
557 
558 	case 'n':
559 	  str->push_back('\n');
560 	  ++this->p_;
561 	  break;
562 
563 	case 'r':
564 	  str->push_back('\r');
565 	  ++this->p_;
566 	  break;
567 
568 	case 't':
569 	  str->push_back('\t');
570 	  ++this->p_;
571 	  break;
572 
573 	case 'u':
574 	  {
575 	    ++this->p_;
576 	    unsigned int rune = 0;
577 	    for (int i = 0; i < 4; i++)
578 	      {
579 		if (this->p_ >= this->pend_)
580 		  {
581 		    this->error("unterminated string");
582 		    return false;
583 		  }
584 		unsigned char c = *this->p_;
585 		++this->p_;
586 		rune <<= 4;
587 		if (c >= '0' && c <= '9')
588 		  rune += c - '0';
589 		else if (c >= 'A' && c <= 'F')
590 		  rune += c - 'A' + 10;
591 		else if (c >= 'a' && c <= 'f')
592 		  rune += c - 'a' + 10;
593 		else
594 		  {
595 		    this->error("invalid hex digit");
596 		    return false;
597 		  }
598 	      }
599 	    Lex::append_char(rune, false, str, Linemap::unknown_location());
600 	  }
601 	  break;
602 
603 	default:
604 	  this->error("unrecognized string escape");
605 	  return false;
606 	}
607     }
608 
609   if (*this->p_ == '"')
610     {
611       ++this->p_;
612       return true;
613     }
614 
615   this->error("unterminated string");
616   return false;
617 }
618 
619 // Report an error if not at EOF.
620 
621 void
check_eof()622 Embedcfg_reader::check_eof()
623 {
624   if (this->skip_whitespace(true))
625     this->error("extraneous data at end of file");
626 }
627 
628 // Skip whitespace.  Return whether there is more to read.
629 
630 bool
skip_whitespace(bool eof_ok)631 Embedcfg_reader::skip_whitespace(bool eof_ok)
632 {
633   while (this->p_ < this->pend_)
634     {
635       switch (*this->p_)
636 	{
637 	case ' ': case '\t': case '\n': case '\r':
638 	  ++this->p_;
639 	  break;
640 	default:
641 	  return true;
642 	}
643     }
644   if (!eof_ok)
645     this->error("unexpected EOF");
646   return false;
647 }
648 
649 // Report an error.
650 
651 void
error(const char * msg)652 Embedcfg_reader::error(const char* msg)
653 {
654   if (!this->data_.empty() && this->p_ != NULL)
655     go_error_at(Linemap::unknown_location(),
656 		"%<-fgo-embedcfg%>: %s: %lu: %s",
657 		this->filename_,
658 		static_cast<unsigned long>(this->p_ - this->data_.data()),
659 		msg);
660   else
661     go_error_at(Linemap::unknown_location(),
662 		"%<-fgo-embedcfg%>: %s: %s",
663 		this->filename_, msg);
664 }
665 
666 // Implement the sort order for a list of embedded files, as discussed
667 // at the docs for embed.FS.
668 
669 class Embedfs_sort
670 {
671  public:
672   bool
673   operator()(const std::string& p1, const std::string& p2) const;
674 
675  private:
676   void
677   split(const std::string&, size_t*, size_t*, size_t*) const;
678 };
679 
680 bool
operator ()(const std::string & p1,const std::string & p2) const681 Embedfs_sort::operator()(const std::string& p1, const std::string& p2) const
682 {
683   size_t dirlen1, elem1, elemlen1;
684   this->split(p1, &dirlen1, &elem1, &elemlen1);
685   size_t dirlen2, elem2, elemlen2;
686   this->split(p2, &dirlen2, &elem2, &elemlen2);
687 
688   if (dirlen1 == 0)
689     {
690       if (dirlen2 > 0)
691 	{
692 	  int i = p2.compare(0, dirlen2, ".");
693 	  if (i != 0)
694 	    return i > 0;
695 	}
696     }
697   else if (dirlen2 == 0)
698     {
699       int i = p1.compare(0, dirlen1, ".");
700       if (i != 0)
701 	return i < 0;
702     }
703   else
704     {
705       int i = p1.compare(0, dirlen1, p2, 0, dirlen2);
706       if (i != 0)
707 	return i < 0;
708     }
709 
710   int i = p1.compare(elem1, elemlen1, p2, elem2, elemlen2);
711   return i < 0;
712 }
713 
714 // Pick out the directory and file name components for comparison.
715 
716 void
split(const std::string & s,size_t * dirlen,size_t * elem,size_t * elemlen) const717 Embedfs_sort::split(const std::string& s, size_t* dirlen, size_t* elem,
718 		    size_t* elemlen) const
719 {
720   size_t len = s.size();
721   if (len > 0 && s[len - 1] == '/')
722     --len;
723   size_t slash = s.rfind('/', len - 1);
724   if (slash == std::string::npos)
725     {
726       *dirlen = 0;
727       *elem = 0;
728       *elemlen = len;
729     }
730   else
731     {
732       *dirlen = slash;
733       *elem = slash + 1;
734       *elemlen = len - (slash + 1);
735     }
736 }
737 
738 // Convert the go:embed directives for a variable into an initializer
739 // for that variable.
740 
741 Expression*
initializer_for_embeds(Type * type,const std::vector<std::string> * embeds,Location loc)742 Gogo::initializer_for_embeds(Type* type,
743 			     const std::vector<std::string>* embeds,
744 			     Location loc)
745 {
746   if (this->embed_patterns_.empty())
747     {
748       go_error_at(loc,
749 		  ("invalid go:embed: build system did not "
750 		   "supply embed configuration"));
751       return Expression::make_error(loc);
752     }
753 
754   type = type->unalias();
755 
756   enum {
757     EMBED_STRING = 0,
758     EMBED_BYTES = 1,
759     EMBED_FS = 2
760   } embed_kind;
761 
762   const Named_type* nt = type->named_type();
763   if (nt != NULL
764       && nt->named_object()->package() != NULL
765       && nt->named_object()->package()->pkgpath() == "embed"
766       && nt->name() == "FS")
767     embed_kind = EMBED_FS;
768   else if (type->is_string_type())
769     embed_kind = EMBED_STRING;
770   else if (type->is_slice_type()
771 	   && type->array_type()->element_type()->integer_type() != NULL
772 	   && type->array_type()->element_type()->integer_type()->is_byte())
773     embed_kind = EMBED_BYTES;
774   else
775     {
776       go_error_at(loc, "invalid type for go:embed");
777       return Expression::make_error(loc);
778     }
779 
780   // The patterns in the go:embed directive(s) are in EMBEDS.  Find
781   // them in the patterns in the embedcfg file.
782 
783   Unordered_set(std::string) have;
784   std::vector<std::string> paths;
785   for (std::vector<std::string>::const_iterator pe = embeds->begin();
786        pe != embeds->end();
787        pe++)
788     {
789       Embed_patterns::const_iterator pp = this->embed_patterns_.find(*pe);
790       if (pp == this->embed_patterns_.end())
791 	{
792 	  go_error_at(loc,
793 		      ("invalid go:embed: build system did not "
794 		       "map pattern %<%s%>"),
795 		      pe->c_str());
796 	  continue;
797 	}
798 
799       // Each pattern in the embedcfg file maps to a list of file
800       // names.  Add those file names to PATHS.
801       for (std::vector<std::string>::const_iterator pf = pp->second.begin();
802 	   pf != pp->second.end();
803 	   pf++)
804 	{
805 	  if (this->embed_files_.find(*pf) == this->embed_files_.end())
806 	    {
807 	      go_error_at(loc,
808 			  ("invalid go:embed: build system did not "
809 			   "map file %<%s%>"),
810 			  pf->c_str());
811 	      continue;
812 	    }
813 
814 	  std::pair<Unordered_set(std::string)::iterator, bool> ins
815 	    = have.insert(*pf);
816 	  if (ins.second)
817 	    {
818 	      const std::string& path(*pf);
819 	      paths.push_back(path);
820 
821 	      if (embed_kind == EMBED_FS)
822 		{
823 		  // Add each required directory, with a trailing slash.
824 		  size_t i = std::string::npos;
825 		  while (i > 0)
826 		    {
827 		      i = path.rfind('/', i);
828 		      if (i == std::string::npos)
829 			break;
830 		      std::string dir = path.substr(0, i + 1);
831 		      ins = have.insert(dir);
832 		      if (ins.second)
833 			paths.push_back(dir);
834 		      --i;
835 		    }
836 		}
837 	    }
838 	}
839     }
840 
841   if (embed_kind == EMBED_STRING || embed_kind == EMBED_BYTES)
842     {
843       if (paths.size() > 1)
844 	{
845 	  go_error_at(loc,
846 		      ("invalid go:embed: multiple files for "
847 		       "string or byte slice"));;
848 	  return Expression::make_error(loc);
849 	}
850 
851       std::string data;
852       if (!read_file(this->embed_files_[paths[0]].c_str(), loc, &data))
853 	return Expression::make_error(loc);
854 
855       Expression* e = Expression::make_string(data, loc);
856       if (embed_kind == EMBED_BYTES)
857 	e = Expression::make_cast(type, e, loc);
858       return e;
859     }
860 
861   std::sort(paths.begin(), paths.end(), Embedfs_sort());
862 
863   if (type->struct_type() == NULL
864       || type->struct_type()->field_count() != 1)
865     {
866       go_error_at(loc,
867 		  ("internal error: embed.FS should be struct type "
868 		   "with one field"));
869       return Expression::make_error(loc);
870     }
871 
872   Type* ptr_type = type->struct_type()->field(0)->type();
873   if (ptr_type->points_to() == NULL)
874     {
875       go_error_at(loc,
876 		  "internal error: embed.FS struct field should be pointer");
877       return Expression::make_error(loc);
878     }
879 
880   Type* slice_type = ptr_type->points_to();
881   if (!slice_type->is_slice_type())
882     {
883       go_error_at(loc,
884 		  ("internal error: embed.FS struct field should be "
885 		   "pointer to slice"));
886       return Expression::make_error(loc);
887     }
888 
889   Type* file_type = slice_type->array_type()->element_type();
890   if (file_type->struct_type() == NULL
891       || (file_type->struct_type()->find_local_field(".embed.name", NULL)
892 	  == NULL)
893       || (file_type->struct_type()->find_local_field(".embed.data", NULL)
894 	  == NULL))
895     {
896       go_error_at(loc,
897 		  ("internal error: embed.FS slice element should be struct "
898 		   "with name and data fields"));
899       return Expression::make_error(loc);
900     }
901 
902   const Struct_field_list* file_fields = file_type->struct_type()->fields();
903   Expression_list* file_vals = new(Expression_list);
904   file_vals->reserve(paths.size());
905   for (std::vector<std::string>::const_iterator pp = paths.begin();
906        pp != paths.end();
907        ++pp)
908     {
909       std::string data;
910       if ((*pp)[pp->size() - 1] != '/')
911 	{
912 	  if (!read_file(this->embed_files_[*pp].c_str(), loc, &data))
913 	    return Expression::make_error(loc);
914 	}
915 
916       Expression_list* field_vals = new(Expression_list);
917       for (Struct_field_list::const_iterator pf = file_fields->begin();
918 	   pf != file_fields->end();
919 	   ++pf)
920 	{
921 	  if (pf->is_field_name(".embed.name"))
922 	    field_vals->push_back(Expression::make_string(*pp, loc));
923 	  else if (pf->is_field_name(".embed.data"))
924 	    field_vals->push_back(Expression::make_string(data, loc));
925 	  else
926 	    {
927 	      // FIXME: The embed.file type has a hash field, which is
928 	      // currently unused.  We should fill it in, but don't.
929 	      // The hash is a SHA256, and we don't have convenient
930 	      // SHA256 code.  Do this later when the field is
931 	      // actually used.
932 	      field_vals->push_back(NULL);
933 	    }
934 	}
935 
936       Expression* file_val =
937 	Expression::make_struct_composite_literal(file_type, field_vals, loc);
938       file_vals->push_back(file_val);
939     }
940 
941   Expression* slice_init =
942     Expression::make_slice_composite_literal(slice_type, file_vals, loc);
943   Expression* fs_init = Expression::make_heap_expression(slice_init, loc);
944   Expression_list* fs_vals = new Expression_list();
945   fs_vals->push_back(fs_init);
946   return Expression::make_struct_composite_literal(type, fs_vals, loc);
947 }
948