@@ -285,14 +285,15 @@ ASTnamed_symbol::ASTnamed_symbol (NodeType node_type, OSLCompilerImpl *comp,
285285
286286
287287bool
288- ASTnamed_symbol::check_reserved (ustring name, OSLCompilerImpl *comp)
288+ ASTnamed_symbol::check_reserved (ustring name, OSLCompilerImpl *comp,
289+ int vflags)
289290{
290291 if (Strutil::starts_with (name, " ___" )) {
291292 comp->error (comp->filename (), comp->lineno (),
292293 " '%s' : sorry, can't start with three underscores" ,
293294 name);
294295 return false ;
295- } else if (name == " this" ) {
296+ } else if (!(vflags & allow_this) && name == " this" ) {
296297 comp->error (comp->filename (), comp->lineno (),
297298 " 'this' not allowed in this context" );
298299 return false ;
@@ -317,9 +318,9 @@ ASTnamed_symbol::previous_decl (ASTNode* node)
317318
318319Symbol*
319320ASTnamed_symbol::validate (ustring name, OSLCompilerImpl *comp,
320- Validation vflags, int allowed)
321+ int vflags, int allowed)
321322{
322- check_reserved (name, comp);
323+ check_reserved (name, comp, vflags );
323324
324325 Symbol *f;
325326 bool shadow = vflags & warn_shadow;
@@ -341,19 +342,35 @@ ASTnamed_symbol::validate (ustring name, OSLCompilerImpl *comp,
341342 if (! f || f->symtype () == allowed)
342343 return f;
343344
344- std::string e = Strutil::format (" '%s' already declared in this scope" ,
345- name);
346- e += previous_decl (f->node ());
347-
345+ std::string msg;
346+ ASTNode* hint = f->node ();
348347 if (shadow) {
349- // special case: only a warning for param to mask global function
348+ // Downgrade to warning if param to mask global function
350349 shadow = f->scope () == 0 && f->symtype () == SymTypeFunction;
350+
351+ // also downgrade to warning if local variable shadowing a field
352+ if (!shadow && f->alias () && f->alias ()->node ()) {
353+ if (f->alias ()->node ()->typespec ().is_structure () &&
354+ f->alias ()->name () == Strutil::format (" this.%s" , name)) {
355+ msg = Strutil::format (" \" %s\" shadows a field with the same name" ,
356+ name);
357+ // FIXME: Would be nice to hint about where the field was
358+ // declared, but f->alias()->node() is the 'this.field' node.
359+ hint = nullptr ;
360+ shadow = true ;
361+ }
362+ }
351363 }
352364
365+ if (msg.empty ())
366+ msg = Strutil::format (" '%s' already declared in this scope" , name);
367+
368+ msg += previous_decl (hint);
369+
353370 if (shadow)
354- comp->warning (comp->filename (), comp->lineno (), " %s" , e );
371+ comp->warning (comp->filename (), comp->lineno (), " %s" , msg );
355372 else
356- comp->error (comp->filename (), comp->lineno (), " %s" , e );
373+ comp->error (comp->filename (), comp->lineno (), " %s" , msg );
357374 }
358375 return f;
359376}
@@ -532,17 +549,19 @@ ASTvariable_declaration::ASTvariable_declaration (OSLCompilerImpl *comp,
532549 const TypeSpec &type,
533550 ustring name, ASTNode *init,
534551 bool isparam, bool ismeta,
535- bool isoutput, bool initlist)
552+ bool isoutput, bool initlist,
553+ bool isthis)
536554 : ASTnamed_symbol (variable_declaration_node, comp, name, init, NULL /* meta */ ),
537555 m_isparam(isparam), m_isoutput(isoutput), m_ismetadata(ismeta),
538556 m_initlist(initlist)
539557{
540- if (! check_reserved ())
558+ int vflags = isthis ? allow_this : 0 ;
559+ if (! check_reserved (m_name, m_compiler, vflags))
541560 return ;
542561
543562 m_typespec = type;
544563 if (! m_ismetadata)
545- validate (warn_function_clash);
564+ validate (vflags | warn_function_clash);
546565
547566 SymType symtype = isparam ? (isoutput ? SymTypeOutputParam : SymTypeParam)
548567 : SymTypeLocal;
@@ -566,6 +585,50 @@ ASTvariable_declaration::ASTvariable_declaration (OSLCompilerImpl *comp,
566585
567586
568587
588+ ASTvariable_declaration::ASTvariable_declaration (OSLCompilerImpl *comp,
589+ const TypeSpec &type,
590+ ASTNode *args)
591+ : ASTvariable_declaration(comp, type, ustring(" this" ), NULL,
592+ false, false, false, false, true)
593+ {
594+ // Push 'this' to front of given arguments
595+ concat (this , args);
596+ if (StructSpec* sspec = type.structure () ? type.structspec () : nullptr ) {
597+ // Add the fields as accessible without 'this', warning about possible
598+ // shadowing/ambiguity as we go.
599+ for (int i = 0 , n = sspec->numfields (); i < n; ++i) {
600+ const auto & field = sspec->field (i);
601+ bool conflict = false ;
602+ for (ref next = args; next; next = next->next ()) {
603+ ASSERT (next->nodetype () == variable_declaration_node);
604+ auto *arg = static_cast <ASTvariable_declaration*>(next.get ());
605+
606+ if (arg->name () == field.name ) {
607+ warning (" argument \" %s\" shadows a field with the same name" ,
608+ field.name );
609+ conflict = true ;
610+ break ;
611+ }
612+ }
613+ if (! conflict) {
614+ ustring qualname = ustring::format (" this.%s" , field.name );
615+ ASSERT (m_compiler->symtab ().find (qualname) != nullptr );
616+ ASSERT (!m_compiler->symtab ().find (field.name ) ||
617+ m_compiler->symtab ().find (field.name )->scope () !=
618+ m_compiler->symtab ().scopeid ());
619+
620+ Symbol* qsym = m_compiler->symtab ().find (qualname);
621+ Symbol *fsym = new Symbol (field.name , field.type ,
622+ qsym->symtype (), this );
623+ fsym->alias (qsym);
624+ m_compiler->symtab ().insert (fsym);
625+ }
626+ }
627+ }
628+ }
629+
630+
631+
569632const char *
570633ASTvariable_declaration::nodetypename () const
571634{
@@ -603,10 +666,10 @@ ASTvariable_declaration::print (std::ostream &out, int indentlevel) const
603666
604667
605668
606- ASTvariable_ref::ASTvariable_ref (OSLCompilerImpl *comp, ustring name)
669+ ASTvariable_ref::ASTvariable_ref (OSLCompilerImpl *comp, ustring name, bool allowthis )
607670 : ASTnamed_symbol (variable_ref_node, comp, name)
608671{
609- m_sym = validate (warn_function_exists);
672+ m_sym = validate (warn_function_exists | (allowthis ? allow_this : 0 ) );
610673 if (m_sym)
611674 m_typespec = m_sym->typespec ();
612675}
@@ -1122,10 +1185,11 @@ ASTtype_constructor::childname (size_t i) const
11221185ASTfunction_call::ASTfunction_call (OSLCompilerImpl *comp, ustring name,
11231186 ASTNode *args, FunctionSymbol *funcsym)
11241187 : ASTnamed_symbol (function_call_node, comp, name, args),
1125- m_poly(funcsym), // Default - resolved symbol or null
1126- m_argread(~1 ), // Default - all args are read except the first
1127- m_argwrite(1 ), // Default - first arg only is written by the op
1128- m_argtakesderivs(0 ) // Default - doesn't take derivs
1188+ m_poly(funcsym), // Default - resolved symbol or null
1189+ m_argread(~1 ), // Default - all args are read except the first
1190+ m_argwrite(1 ), // Default - first arg only is written by the op
1191+ m_argtakesderivs(0 ), // Default - doesn't take derivs
1192+ m_method(false )
11291193{
11301194 m_sym = funcsym ? funcsym : validate (err_must_exist); // Look it up.
11311195 if (! m_sym || is_struct_ctr ())
@@ -1139,10 +1203,24 @@ ASTfunction_call::ASTfunction_call (OSLCompilerImpl *comp, ustring name,
11391203
11401204
11411205
1206+ void
1207+ ASTfunction_call::method_from_function (ASTNode* thisRef)
1208+ {
1209+ ASSERT (m_method == false );
1210+ ASSERT (m_children.size () == 1 );
1211+ m_method = true ;
1212+ if (m_children[0 ])
1213+ thisRef->append (args ().get ());
1214+
1215+ m_children[0 ] = thisRef;
1216+ }
1217+
1218+
1219+
11421220const char *
11431221ASTfunction_call::childname (size_t i) const
11441222{
1145- return ustring::format (" param%d" , (int )i).c_str ();
1223+ return (i || !m_method ? ustring::format (" param%d" , (int )i) : ustring ( " this " ) ).c_str ();
11461224}
11471225
11481226
0 commit comments