@@ -325,14 +325,15 @@ ASTnamed_symbol::ASTnamed_symbol (NodeType node_type, OSLCompilerImpl *comp,
325325
326326
327327bool
328- ASTnamed_symbol::check_reserved (ustring name, OSLCompilerImpl *comp)
328+ ASTnamed_symbol::check_reserved (ustring name, OSLCompilerImpl *comp,
329+ int vflags)
329330{
330331 if (Strutil::starts_with (name, " ___" )) {
331332 comp->error (comp->filename (), comp->lineno (),
332333 " '%s' : sorry, can't start with three underscores" ,
333334 name);
334335 return false ;
335- } else if (name == " this" ) {
336+ } else if (!(vflags & allow_this) && name == " this" ) {
336337 comp->error (comp->filename (), comp->lineno (),
337338 " 'this' not allowed in this context" );
338339 return false ;
@@ -357,9 +358,9 @@ ASTnamed_symbol::previous_decl (ASTNode* node)
357358
358359Symbol*
359360ASTnamed_symbol::validate (ustring name, OSLCompilerImpl *comp,
360- Validation vflags, int allowed)
361+ int vflags, int allowed)
361362{
362- check_reserved (name, comp);
363+ check_reserved (name, comp, vflags );
363364
364365 Symbol *f;
365366 bool shadow = vflags & warn_shadow;
@@ -381,19 +382,35 @@ ASTnamed_symbol::validate (ustring name, OSLCompilerImpl *comp,
381382 if (! f || f->symtype () == allowed)
382383 return f;
383384
384- std::string e = Strutil::format (" '%s' already declared in this scope" ,
385- name);
386- e += previous_decl (f->node ());
387-
385+ std::string msg;
386+ ASTNode* hint = f->node ();
388387 if (shadow) {
389- // special case: only a warning for param to mask global function
388+ // Downgrade to warning if param to mask global function
390389 shadow = f->scope () == 0 && f->symtype () == SymTypeFunction;
390+
391+ // also downgrade to warning if local variable shadowing a field
392+ if (!shadow && f->alias () && f->alias ()->node ()) {
393+ if (f->alias ()->node ()->typespec ().is_structure () &&
394+ f->alias ()->name () == Strutil::format (" this.%s" , name)) {
395+ msg = Strutil::format (" \" %s\" shadows a field with the same name" ,
396+ name);
397+ // FIXME: Would be nice to hint about where the field was
398+ // declared, but f->alias()->node() is the 'this.field' node.
399+ hint = nullptr ;
400+ shadow = true ;
401+ }
402+ }
391403 }
392404
405+ if (msg.empty ())
406+ msg = Strutil::format (" '%s' already declared in this scope" , name);
407+
408+ msg += previous_decl (hint);
409+
393410 if (shadow)
394- comp->warning (comp->filename (), comp->lineno (), " %s" , e );
411+ comp->warning (comp->filename (), comp->lineno (), " %s" , msg );
395412 else
396- comp->error (comp->filename (), comp->lineno (), " %s" , e );
413+ comp->error (comp->filename (), comp->lineno (), " %s" , msg );
397414 }
398415 return f;
399416}
@@ -598,12 +615,14 @@ ASTvariable_declaration::ASTvariable_declaration (OSLCompilerImpl *comp,
598615 const TypeSpec &type,
599616 ustring name, ASTNode *init,
600617 bool isparam, bool ismeta,
601- bool isoutput, bool initlist)
618+ bool isoutput, bool initlist,
619+ bool isthis)
602620 : ASTnamed_symbol (variable_declaration_node, comp, name, init, NULL /* meta */ ),
603621 m_isparam(isparam), m_isoutput(isoutput), m_ismetadata(ismeta),
604622 m_initlist(initlist)
605623{
606- if (! check_reserved ())
624+ int vflags = isthis ? allow_this : 0 ;
625+ if (! check_reserved (m_name, m_compiler, vflags))
607626 return ;
608627
609628 if (m_initlist && init) {
@@ -614,7 +633,7 @@ ASTvariable_declaration::ASTvariable_declaration (OSLCompilerImpl *comp,
614633
615634 m_typespec = type;
616635 if (! m_ismetadata)
617- validate (warn_function_clash);
636+ validate (vflags | warn_function_clash);
618637
619638 SymType symtype = isparam ? (isoutput ? SymTypeOutputParam : SymTypeParam)
620639 : SymTypeLocal;
@@ -638,6 +657,50 @@ ASTvariable_declaration::ASTvariable_declaration (OSLCompilerImpl *comp,
638657
639658
640659
660+ ASTvariable_declaration::ASTvariable_declaration (OSLCompilerImpl *comp,
661+ const TypeSpec &type,
662+ ASTNode *args)
663+ : ASTvariable_declaration(comp, type, ustring(" this" ), NULL,
664+ false, false, false, false, true)
665+ {
666+ // Push 'this' to front of given arguments
667+ concat (this , args);
668+ if (StructSpec* sspec = type.structure () ? type.structspec () : nullptr ) {
669+ // Add the fields as accessible without 'this', warning about possible
670+ // shadowing/ambiguity as we go.
671+ for (int i = 0 , n = sspec->numfields (); i < n; ++i) {
672+ const auto & field = sspec->field (i);
673+ bool conflict = false ;
674+ for (ref next = args; next; next = next->next ()) {
675+ ASSERT (next->nodetype () == variable_declaration_node);
676+ auto *arg = static_cast <ASTvariable_declaration*>(next.get ());
677+
678+ if (arg->name () == field.name ) {
679+ warning (" argument \" %s\" shadows a field with the same name" ,
680+ field.name );
681+ conflict = true ;
682+ break ;
683+ }
684+ }
685+ if (! conflict) {
686+ ustring qualname = ustring::format (" this.%s" , field.name );
687+ ASSERT (m_compiler->symtab ().find (qualname) != nullptr );
688+ ASSERT (!m_compiler->symtab ().find (field.name ) ||
689+ m_compiler->symtab ().find (field.name )->scope () !=
690+ m_compiler->symtab ().scopeid ());
691+
692+ Symbol* qsym = m_compiler->symtab ().find (qualname);
693+ Symbol *fsym = new Symbol (field.name , field.type ,
694+ qsym->symtype (), this );
695+ fsym->alias (qsym);
696+ m_compiler->symtab ().insert (fsym);
697+ }
698+ }
699+ }
700+ }
701+
702+
703+
641704const char *
642705ASTvariable_declaration::nodetypename () const
643706{
@@ -675,10 +738,10 @@ ASTvariable_declaration::print (std::ostream &out, int indentlevel) const
675738
676739
677740
678- ASTvariable_ref::ASTvariable_ref (OSLCompilerImpl *comp, ustring name)
741+ ASTvariable_ref::ASTvariable_ref (OSLCompilerImpl *comp, ustring name, bool allowthis )
679742 : ASTnamed_symbol (variable_ref_node, comp, name)
680743{
681- m_sym = validate (warn_function_exists);
744+ m_sym = validate (warn_function_exists | (allowthis ? allow_this : 0 ) );
682745 if (m_sym)
683746 m_typespec = m_sym->typespec ();
684747}
@@ -1195,10 +1258,11 @@ ASTtype_constructor::childname (size_t i) const
11951258ASTfunction_call::ASTfunction_call (OSLCompilerImpl *comp, ustring name,
11961259 ASTNode *args, FunctionSymbol *funcsym)
11971260 : ASTnamed_symbol (function_call_node, comp, name, args),
1198- m_poly(funcsym), // Default - resolved symbol or null
1199- m_argread(~1 ), // Default - all args are read except the first
1200- m_argwrite(1 ), // Default - first arg only is written by the op
1201- m_argtakesderivs(0 ) // Default - doesn't take derivs
1261+ m_poly(funcsym), // Default - resolved symbol or null
1262+ m_argread(~1 ), // Default - all args are read except the first
1263+ m_argwrite(1 ), // Default - first arg only is written by the op
1264+ m_argtakesderivs(0 ), // Default - doesn't take derivs
1265+ m_method(false )
12021266{
12031267 m_sym = funcsym ? funcsym : validate (err_must_exist); // Look it up.
12041268 if (! m_sym || is_struct_ctr ())
@@ -1212,10 +1276,24 @@ ASTfunction_call::ASTfunction_call (OSLCompilerImpl *comp, ustring name,
12121276
12131277
12141278
1279+ void
1280+ ASTfunction_call::method_from_function (ASTNode* thisRef)
1281+ {
1282+ ASSERT (m_method == false );
1283+ ASSERT (m_children.size () == 1 );
1284+ m_method = true ;
1285+ if (m_children[0 ])
1286+ thisRef->append (args ().get ());
1287+
1288+ m_children[0 ] = thisRef;
1289+ }
1290+
1291+
1292+
12151293const char *
12161294ASTfunction_call::childname (size_t i) const
12171295{
1218- return ustring::format (" param%d" , (int )i).c_str ();
1296+ return (i || !m_method ? ustring::format (" param%d" , (int )i) : ustring ( " this " ) ).c_str ();
12191297}
12201298
12211299
0 commit comments