aboutsummaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2011-02-24 04:30:34 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2011-02-24 04:30:34 +0000
commitcd34c8436057524c36b1999828643da0bd41601b (patch)
treedea5d961e05999b43cf8c2f3a02eb91f44091a60 /gcc/go
parentacabc10c983db7b55fda3b02f7c0a9d779e0245a (diff)
downloadgcc-cd34c8436057524c36b1999828643da0bd41601b.zip
gcc-cd34c8436057524c36b1999828643da0bd41601b.tar.gz
gcc-cd34c8436057524c36b1999828643da0bd41601b.tar.bz2
Avoid infinite loop in field_reference.
From-SVN: r170457
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/gofrontend/types.cc32
-rw-r--r--gcc/go/gofrontend/types.h10
2 files changed, 40 insertions, 2 deletions
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index 1e39731..806226f 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -3583,7 +3583,8 @@ Struct_type::field_reference(Expression* struct_expr, const std::string& name,
source_location location) const
{
unsigned int depth;
- return this->field_reference_depth(struct_expr, name, location, &depth);
+ return this->field_reference_depth(struct_expr, name, location, NULL,
+ &depth);
}
// Return an expression for a field, along with the depth at which it
@@ -3593,6 +3594,7 @@ Field_reference_expression*
Struct_type::field_reference_depth(Expression* struct_expr,
const std::string& name,
source_location location,
+ Saw_named_type* saw,
unsigned int* depth) const
{
const Struct_field_list* fields = this->fields_;
@@ -3628,13 +3630,41 @@ Struct_type::field_reference_depth(Expression* struct_expr,
if (st == NULL)
continue;
+ Saw_named_type* hold_saw = saw;
+ Saw_named_type saw_here;
+ Named_type* nt = pf->type()->named_type();
+ if (nt == NULL)
+ nt = pf->type()->deref()->named_type();
+ if (nt != NULL)
+ {
+ Saw_named_type* q;
+ for (q = saw; q != NULL; q = q->next)
+ {
+ if (q->nt == nt)
+ {
+ // If this is an error, it will be reported
+ // elsewhere.
+ break;
+ }
+ }
+ if (q != NULL)
+ continue;
+ saw_here.next = saw;
+ saw_here.nt = nt;
+ saw = &saw_here;
+ }
+
// Look for a reference using a NULL struct expression. If we
// find one, fill in the struct expression with a reference to
// this field.
unsigned int subdepth;
Field_reference_expression* sub = st->field_reference_depth(NULL, name,
location,
+ saw,
&subdepth);
+
+ saw = hold_saw;
+
if (sub == NULL)
continue;
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index b428077..b0dbefe 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -1980,9 +1980,17 @@ class Struct_type : public Type
do_export(Export*) const;
private:
+ // Used to avoid infinite loops in field_reference_depth.
+ struct Saw_named_type
+ {
+ Saw_named_type* next;
+ Named_type* nt;
+ };
+
Field_reference_expression*
field_reference_depth(Expression* struct_expr, const std::string& name,
- source_location, unsigned int* depth) const;
+ source_location, Saw_named_type*,
+ unsigned int* depth) const;
static Type*
make_struct_type_descriptor_type();