diff --git a/Test/100scope.vert b/Test/100scope.vert new file mode 100644 index 0000000000000000000000000000000000000000..0076846ebefa75150bd82a57378725ecb5701870 --- /dev/null +++ b/Test/100scope.vert @@ -0,0 +1,64 @@ +#version 100 + +int f(int a, int b, int c) +{ + int a = b; // ERROR, redefinition + + { + float a = float(a) + 1.0; + } + + return a; +} + +int f(int a, int b, int c); // okay to redeclare + +bool b; +float b(int a); // ERROR: redefinition + +float f; // ERROR: redefinition +float tan; // ERROR: redefines built-in function +float sin(float x); // ERROR: can't overload built-in functions +float cos(float x) // ERROR: can't overload built-in functions +{ + return 1.0; +} + +invariant gl_Position; + +void main() +{ + int g(); // ERROR: no local function declarations + g(); + + float sin; // okay + sin; + + f(1,2,3); + + float f; // hides f() + f = 3.0; + + gl_Position = vec4(f); + + for (int f = 0; f < 10; ++f) + ++f; + + int x = 1; + { + float x = 2.0, /* 2nd x visible here */ y = x; // y is initialized to 2 + int z = z; // ERROR: z not previously defined. + } + { + int x = x; // x is initialized to '1' + } + + struct S + { + int x; + }; + { + S S = S(0); // 'S' is only visible as a struct and constructor + S.x; // 'S' is now visible as a variable + } +} diff --git a/Test/baseResults/100scope.vert.out b/Test/baseResults/100scope.vert.out new file mode 100644 index 0000000000000000000000000000000000000000..97ca557064b4dedac78f690c202411dcf0426294 --- /dev/null +++ b/Test/baseResults/100scope.vert.out @@ -0,0 +1,104 @@ +ERROR: 0:5: 'a' : redefinition +ERROR: 0:17: 'b' : illegal redeclaration +ERROR: 0:19: 'f' : redefinition +ERROR: 0:20: 'tan' : redefinition +ERROR: 0:31: 'local function declaration' : not supported with this profile: es +ERROR: 0:50: 'z' : undeclared identifier +ERROR: 0:50: 'z' : redefinition +ERROR: 7 compilation errors. No code generated. + +ERROR: node is still EOpNull! +0:3 Function Definition: f(i1;i1;i1; (highp int) +0:3 Function Parameters: +0:3 'a' (in highp int) +0:3 'b' (in highp int) +0:3 'c' (in highp int) +0:? Sequence +0:8 Sequence +0:8 Sequence +0:8 move second child to first child (highp float) +0:8 'a' (highp float) +0:8 add (highp float) +0:8 Convert int to float (highp float) +0:8 'a' (in highp int) +0:8 Constant: +0:8 1.000000 +0:11 Branch: Return with expression +0:11 'a' (in highp int) +0:22 Function Definition: cos(f1; (highp float) +0:22 Function Parameters: +0:22 'x' (in highp float) +0:24 Sequence +0:24 Branch: Return with expression +0:24 Constant: +0:24 1.000000 +0:29 Function Definition: main( (void) +0:29 Function Parameters: +0:? Sequence +0:32 Function Call: g( (highp int) +0:35 'sin' (highp float) +0:37 Function Call: f(i1;i1;i1; (highp int) +0:37 Constant: +0:37 1 (const int) +0:37 Constant: +0:37 2 (const int) +0:37 Constant: +0:37 3 (const int) +0:40 move second child to first child (highp float) +0:40 'f' (highp float) +0:40 Constant: +0:40 3.000000 +0:42 move second child to first child (highp 4-component vector of float) +0:42 'gl_Position' (invariant gl_Position highp 4-component vector of float) +0:42 Construct vec4 (highp 4-component vector of float) +0:42 'f' (highp float) +0:44 Sequence +0:44 Sequence +0:44 move second child to first child (highp int) +0:44 'f' (highp int) +0:44 Constant: +0:44 0 (const int) +0:44 Loop with condition tested first +0:44 Loop Condition +0:44 Compare Less Than (bool) +0:44 'f' (highp int) +0:44 Constant: +0:44 10 (const int) +0:44 Loop Body +0:45 Pre-Increment (highp int) +0:45 'f' (highp int) +0:44 Loop Terminal Expression +0:44 Pre-Increment (highp int) +0:44 'f' (highp int) +0:47 Sequence +0:47 move second child to first child (highp int) +0:47 'x' (highp int) +0:47 Constant: +0:47 1 (const int) +0:49 Sequence +0:49 Sequence +0:49 move second child to first child (highp float) +0:49 'x' (highp float) +0:49 Constant: +0:49 2.000000 +0:49 move second child to first child (highp float) +0:49 'y' (highp float) +0:49 'x' (highp float) +0:53 Sequence +0:53 Sequence +0:53 move second child to first child (highp int) +0:53 'x' (highp int) +0:53 'x' (highp int) +0:61 Sequence +0:61 Sequence +0:61 move second child to first child (structure) +0:61 'S' (structure) +0:61 Constant: +0:61 0 (const int) +0:62 x: direct index for structure (highp int) +0:62 'S' (structure) +0:62 Constant: +0:62 0 (const int) +0:? Linker Objects +0:? 'b' (bool) + diff --git a/Test/baseResults/300scope.vert.out b/Test/baseResults/300scope.vert.out index 55699cbae3d75b01fd815e3c97ed659f1d20c11d..fc5bf6c05f8b44e5d8ad9d43efe365e8c0e6312e 100644 --- a/Test/baseResults/300scope.vert.out +++ b/Test/baseResults/300scope.vert.out @@ -2,8 +2,8 @@ ERROR: 0:5: 'a' : redefinition ERROR: 0:17: 'b' : illegal redeclaration ERROR: 0:19: 'f' : redefinition ERROR: 0:20: 'tan' : redefinition -ERROR: 0:21: 'redeclaration of built-in function' : not supported with this profile: es -ERROR: 0:22: 'redeclaration of built-in function' : not supported with this profile: es +ERROR: 0:21: 'redeclaration of built-in function' : no longer supported in es profile; removed in version 300 +ERROR: 0:22: 'redeclaration of built-in function' : no longer supported in es profile; removed in version 300 ERROR: 0:31: 'local function declaration' : not supported with this profile: es ERROR: 0:50: 'z' : undeclared identifier ERROR: 0:50: 'z' : redefinition diff --git a/Test/testlist b/Test/testlist index 24fd1e594f0796fe4b9b5f1eb4ad88467c039068..0789f1b5b805fc90a59da4125d242b66da138ced 100644 --- a/Test/testlist +++ b/Test/testlist @@ -39,6 +39,7 @@ forwardRef.frag uint.frag switch.frag tokenLength.vert +100scope.vert 300scope.vert 400.frag 420.vert diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 12c0a40bd4bdc249c573db880a5711bce9300615..36b3c9d86fade2a55b00b1f1b69bb4a953fc20a2 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -652,6 +652,53 @@ TIntermTyped* TParseContext::handleDotDereference(TSourceLoc loc, TIntermTyped* return result; } +// +// Handle seeing a function declarator in the grammar. This is the precursor +// to recognizing a function prototype or function definition. +// +TFunction* TParseContext::handleFunctionDeclarator(TSourceLoc loc, TFunction& function) +{ + // ES can't declare prototypes inside functions + if (! symbolTable.atGlobalLevel()) + requireProfile(loc, static_cast<EProfileMask>(~EEsProfileMask), "local function declaration"); + + // + // Multiple declarations of the same function are allowed. + // + // If this is a definition, the definition production code will check for redefinitions + // (we don't know at this point if it's a definition or not). + // + // Redeclarations (full prototype match) are allowed. But, return types and parameter qualifiers must match. + // + // ES does not allow redeclaring or hiding of built-in functions. + // + bool builtIn; + TSymbol* symbol = symbolTable.find(function.getMangledName(), &builtIn); + if (symbol && symbol->getAsFunction() && builtIn) + requireNotRemoved(loc, EEsProfile, 300, "redeclaration of built-in function"); + const TFunction* prevDec = symbol ? symbol->getAsFunction() : 0; + if (prevDec) { + if (prevDec->getReturnType() != function.getReturnType()) { + error(loc, "overloaded functions must have the same return type", function.getReturnType().getCompleteTypeString().c_str(), ""); + } + for (int i = 0; i < prevDec->getParamCount(); ++i) { + if ((*prevDec)[i].type->getQualifier().storage != function[i].type->getQualifier().storage) + error(loc, "overloaded functions must have the same parameter qualifiers", function[i].type->getStorageQualifierString(), ""); + } + } + + + if (! symbolTable.insert(function)) + error(loc, "illegal redeclaration", function.getName().c_str(), ""); + + // + // If this is a redeclaration, it could also be a definition, + // in which case, we want to use the variable names from this one, and not the one that's + // being redeclared. So, pass back this declaration, not the one in the symbol table. + // + return &function; +} + // // Handle seeing a function prototype in the grammar. This includes what may // become a full definition, as a full definition looks like a prototype diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index 6f45b5c3c2ab015288bbe6e5a74cae1fdb32a44a..2226f25bb74d48270f7c8c02c2d9f997e0c036f2 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -85,6 +85,7 @@ public: TIntermTyped* handleVariable(TSourceLoc, TSymbol* symbol, TString* string); TIntermTyped* handleBracketDereference(TSourceLoc, TIntermTyped* base, TIntermTyped* index); TIntermTyped* handleDotDereference(TSourceLoc, TIntermTyped* base, TString& field); + TFunction* handleFunctionDeclarator(TSourceLoc loc, TFunction& function); TIntermAggregate* handleFunctionPrototype(TSourceLoc, TFunction&); TIntermTyped* handleFunctionCall(TSourceLoc, TFunction*, TIntermNode*, TIntermAggregate*); TFunction* handleConstructorCall(TSourceLoc, TPublicType&); diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index af986bdf2ac48a02f12c67d89ad74dfdde44ef8c..3443ded29778641cebe3def1317b66e9b444849e 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -791,45 +791,8 @@ identifier_list function_prototype : function_declarator RIGHT_PAREN { - // ES can't declare prototypes inside functions - if (! parseContext.symbolTable.atGlobalLevel()) - parseContext.requireProfile($2.loc, static_cast<EProfileMask>(~EEsProfileMask), "local function declaration"); - - // - // Multiple declarations of the same function are allowed. - // - // If this is a definition, the definition production code will check for redefinitions - // (we don't know at this point if it's a definition or not). - // - // Redeclarations (full prototype match) are allowed. But, return types and parameter qualifiers must match. - // - // ES does not allow redeclaring or hiding of built-in functions. - // - bool builtIn; - TSymbol* symbol = parseContext.symbolTable.find($1->getMangledName(), &builtIn); - if (symbol && symbol->getAsFunction() && builtIn) - parseContext.requireProfile($2.loc, static_cast<EProfileMask>(~EEsProfileMask), "redeclaration of built-in function"); - const TFunction* prevDec = symbol ? symbol->getAsFunction() : 0; - if (prevDec) { - if (prevDec->getReturnType() != $1->getReturnType()) { - parseContext.error($2.loc, "overloaded functions must have the same return type", $1->getReturnType().getCompleteTypeString().c_str(), ""); - } - for (int i = 0; i < prevDec->getParamCount(); ++i) { - if ((*prevDec)[i].type->getQualifier().storage != (*$1)[i].type->getQualifier().storage) - parseContext.error($2.loc, "overloaded functions must have the same parameter qualifiers", (*$1)[i].type->getStorageQualifierString(), ""); - } - } - - // - // If this is a redeclaration, it could also be a definition, - // in which case, we want to use the variable names from this one, and not the one that's - // being redeclared. So, pass back up this declaration, not the one in the symbol table. - // - $$.function = $1; + $$.function = parseContext.handleFunctionDeclarator($2.loc, *$1); $$.loc = $2.loc; - - if (! parseContext.symbolTable.insert(*$$.function)) - parseContext.error($2.loc, "illegal redeclaration", $$.function->getName().c_str(), ""); } ;