Skip to content

Commit 2e2e2fe

Browse files
authored
oslc: Add warning for detection of duplicate functions in the same scope. (#746)
Previously, if you for some reason defined two identical functions in the same scope (including redefining a "built-in" function exactly in the outermost scope), it would just silently accept it, and then you wouldn't be sure which one would actually end up getting called. For now it's a warning. After people have had a chance to scrub their code bases, perhaps we will upgrade this to a full error in a future release.
1 parent d0f158a commit 2e2e2fe

9 files changed

Lines changed: 107 additions & 50 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ TESTSUITE ( and-or-not-synonyms aastep arithmetic array array-derivs array-range
267267
operator-overloading
268268
oslc-comma oslc-D
269269
oslc-err-arrayindex oslc-err-closuremul oslc-err-field
270-
oslc-err-format oslc-err-intoverflow
270+
oslc-err-format oslc-err-funcredef oslc-err-intoverflow
271271
oslc-err-noreturn oslc-err-notfunc
272272
oslc-err-outputparamvararray oslc-err-paramdefault
273273
oslc-err-struct-array-init oslc-err-struct-ctr

src/liboslcomp/ast.cpp

Lines changed: 73 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,45 @@ ASTNode::type_c_str (const TypeSpec &type) const
251251

252252

253253

254+
void
255+
ASTNode::list_to_vec (const ref &A, std::vector<ref> &vec)
256+
{
257+
vec.clear ();
258+
for (ref node = A; node; node = node->next())
259+
vec.push_back (node);
260+
}
261+
262+
263+
264+
ASTNode::ref
265+
ASTNode::vec_to_list (std::vector<ref> &vec)
266+
{
267+
if (vec.size()) {
268+
for (size_t i = 0; i < vec.size()-1; ++i)
269+
vec[i]->m_next = vec[i+1];
270+
vec[vec.size()-1]->m_next = NULL;
271+
return vec[0];
272+
} else {
273+
return ref();
274+
}
275+
}
276+
277+
278+
279+
std::string
280+
ASTNode::list_to_types_string (const ASTNode *node)
281+
{
282+
std::ostringstream result;
283+
for (int i = 0; node; node = node->nextptr(), ++i) {
284+
if (i)
285+
result << ", ";
286+
result << node->typespec();
287+
}
288+
return result.str();
289+
}
290+
291+
292+
254293
ASTshader_declaration::ASTshader_declaration (OSLCompilerImpl *comp,
255294
int stype, ustring name, ASTNode *form,
256295
ASTNode *stmts, ASTNode *meta)
@@ -304,29 +343,31 @@ ASTshader_declaration::shadertypename () const
304343

305344
ASTfunction_declaration::ASTfunction_declaration (OSLCompilerImpl *comp,
306345
TypeSpec type, ustring name,
307-
ASTNode *form, ASTNode *stmts, ASTNode *meta)
346+
ASTNode *form, ASTNode *stmts, ASTNode *meta,
347+
int sourceline_start)
308348
: ASTNode (function_declaration_node, comp, 0, meta, form, stmts),
309349
m_name(name), m_sym(NULL), m_is_builtin(false)
310350
{
311-
m_typespec = type;
312-
Symbol *f = comp->symtab().clash (name);
313-
if (f && f->symtype() != SymTypeFunction) {
314-
error ("\"%s\" already declared in this scope as a ", name.c_str(),
315-
f->typespec().string().c_str());
316-
// FIXME -- print the file and line of the other definition
317-
f = NULL;
318-
}
351+
// Some trickery -- the compiler's idea of the "current" source line
352+
// is the END of the function body, so if a hint was passed about the
353+
// start of the declaration, substitute that.
354+
if (sourceline_start >= 0)
355+
m_sourceline = sourceline_start;
319356

320-
// FIXME -- allow multiple function declarations, but only if they
321-
// aren't the same polymorphic type.
357+
if (Strutil::starts_with (name, "___"))
358+
error ("\"%s\" : sorry, can't start with three underscores", name);
322359

323-
if (name[0] == '_' && name[1] == '_' && name[2] == '_') {
324-
error ("\"%s\" : sorry, can't start with three underscores",
325-
name.c_str());
360+
// Get a pointer to the first of the existing symbols of that name.
361+
Symbol *existing_syms = comp->symtab().clash (name);
362+
if (existing_syms && existing_syms->symtype() != SymTypeFunction) {
363+
error ("\"%s\" already declared in this scope as a %s",
364+
name, existing_syms->typespec());
365+
// FIXME -- print the file and line of the other definition
366+
existing_syms = NULL;
326367
}
327368

328-
m_sym = new FunctionSymbol (name, type, this);
329-
func()->nextpoly ((FunctionSymbol *)f);
369+
// Build up the argument signature for this declared function
370+
m_typespec = type;
330371
std::string argcodes = oslcompiler->code_from_type (m_typespec);
331372
for (ASTNode *arg = form; arg; arg = arg->nextptr()) {
332373
const TypeSpec &t (arg->typespec());
@@ -341,6 +382,22 @@ ASTfunction_declaration::ASTfunction_declaration (OSLCompilerImpl *comp,
341382
v->error ("function parameter '%s' may not have a default initializer.",
342383
v->name().c_str());
343384
}
385+
386+
// Allow multiple function declarations, but only if they aren't the
387+
// same polymorphic type in the same scope.
388+
int current_scope = oslcompiler->symtab().scopeid();
389+
for (FunctionSymbol *f = reinterpret_cast<FunctionSymbol *>(existing_syms);
390+
f; f = f->nextpoly()) {
391+
if (f->argcodes() == argcodes && f->scope() == current_scope) {
392+
warning ("Function '%s %s (%s)' declared twice in the same scope",
393+
type, name, list_to_types_string(form));
394+
}
395+
}
396+
397+
398+
m_sym = new FunctionSymbol (name, type, this);
399+
func()->nextpoly ((FunctionSymbol *)existing_syms);
400+
344401
func()->argcodes (ustring (argcodes));
345402
oslcompiler->symtab().insert (m_sym);
346403

src/liboslcomp/ast.h

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -248,24 +248,15 @@ class ASTNode : public OIIO::RefCnt {
248248

249249
/// Flatten a list of nodes (headed by A) into a vector of node refs
250250
/// (vec).
251-
static void list_to_vec (const ref &A, std::vector<ref> &vec) {
252-
vec.clear ();
253-
for (ref node = A; node; node = node->next())
254-
vec.push_back (node);
255-
}
251+
static void list_to_vec (const ref &A, std::vector<ref> &vec);
256252

257253
/// Turn a vector of node refs into a list of nodes, returning its
258254
/// head.
259-
static ref vec_to_list (std::vector<ref> &vec) {
260-
if (vec.size()) {
261-
for (size_t i = 0; i < vec.size()-1; ++i)
262-
vec[i]->m_next = vec[i+1];
263-
vec[vec.size()-1]->m_next = NULL;
264-
return vec[0];
265-
} else {
266-
return ref();
267-
}
268-
}
255+
static ref vec_to_list (std::vector<ref> &vec);
256+
257+
/// Generate a comma-separated string of data types of the list headed
258+
/// by node (for example, "float, int, string").
259+
static std::string list_to_types_string (const ASTNode *node);
269260

270261
/// Return the number of child nodes.
271262
///
@@ -420,7 +411,8 @@ class ASTfunction_declaration : public ASTNode
420411
{
421412
public:
422413
ASTfunction_declaration (OSLCompilerImpl *comp, TypeSpec type, ustring name,
423-
ASTNode *form, ASTNode *stmts, ASTNode *meta=NULL);
414+
ASTNode *form, ASTNode *stmts, ASTNode *meta=NULL,
415+
int sourceline_start=-1);
424416
const char *nodetypename () const { return "function_declaration"; }
425417
const char *childname (size_t i) const;
426418
void print (std::ostream &out, int indentlevel=0) const;

src/liboslcomp/oslgram.y

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,12 @@ shader_or_function_declaration
194194
f = new ASTfunction_declaration (oslcompiler,
195195
typespec_stack.top(),
196196
ustring($2), $7 /*formals*/,
197-
$11 /*statements*/);
197+
$11 /*statements*/,
198+
NULL /*metadata*/,
199+
@2.first_line);
198200
oslcompiler->remember_function_decl (f);
199201
f->add_meta (concat($4, $10));
200202
$$ = f;
201-
$$->sourceline (@2.first_line);
202203
typespec_stack.pop ();
203204
} else {
204205
// Shader declaration

src/shaders/color2.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -181,18 +181,6 @@ color2 clamp(color2 c, float minval, float maxval)
181181
return clamp(c, color2(minval, minval), color2(maxval, maxval));
182182
}
183183

184-
color2 pow(color2 base, color2 power)
185-
{
186-
return color2(pow(base.r, power.r),
187-
pow(base.a, power.a));
188-
}
189-
190-
color2 pow(color2 base, float power)
191-
{
192-
return color2(pow(base.r, power),
193-
pow(base.a, power));
194-
}
195-
196184
color2 max(color2 a, color2 b)
197185
{
198186
return color2(max(a.r, b.r),

src/shaders/stdosl.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,20 +60,20 @@
6060
color name (color x) BUILTIN; \
6161
float name (float x) BUILTIN;
6262

63+
// Declare name (T,T) for T in {triples,float}
6364
#define PERCOMP2(name) \
6465
normal name (normal x, normal y) BUILTIN; \
6566
vector name (vector x, vector y) BUILTIN; \
6667
point name (point x, point y) BUILTIN; \
6768
color name (color x, color y) BUILTIN; \
6869
float name (float x, float y) BUILTIN;
6970

71+
// Declare name(T,float) for T in {triples}
7072
#define PERCOMP2F(name) \
7173
normal name (normal x, float y) BUILTIN; \
7274
vector name (vector x, float y) BUILTIN; \
7375
point name (point x, float y) BUILTIN; \
74-
color name (color x, float y) BUILTIN; \
75-
float name (float x, float y) BUILTIN;
76-
76+
color name (color x, float y) BUILTIN;
7777

7878
// Basic math
7979
normal degrees (normal x) { return x*(180.0/M_PI); }
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
test.osl:1: warning: Function 'point abs (point)' declared twice in the same scope
2+
Compiled test.osl -> test.oso
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env python
2+
3+
# command = oslc("test.osl")
4+
# don't even need that -- it's automatic
5+
failureok = 1 # this test is expected to have oslc errors
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
point abs (point p)
2+
{
3+
printf ("Alternate abs!\n");
4+
return point (abs(p[0]), abs(p[1]), abs(p[2]));
5+
}
6+
7+
8+
shader test()
9+
{
10+
printf ("abs(P)= %g\n", abs(P));
11+
}
12+

0 commit comments

Comments
 (0)