glsl: Don't allow vertex shader input arrays until GLSL 1.50.
[mesa.git] / src / glsl / glsl_parser.yy
index f12336883483147ffbd1061b43bab4a4b4d2a3e6..78f5bf6f4f2038e318e09f2b27a9c4713136b278 100644 (file)
@@ -79,6 +79,7 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg)
    ast_case_label_list *case_label_list;
    ast_case_statement *case_statement;
    ast_case_statement_list *case_statement_list;
+   ast_interface_block *interface_block;
 
    struct {
       ast_node *cond;
@@ -108,10 +109,13 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg)
 %token USAMPLER2DARRAY USAMPLERCUBEARRAY
 %token SAMPLER2DRECT ISAMPLER2DRECT USAMPLER2DRECT SAMPLER2DRECTSHADOW
 %token SAMPLERBUFFER ISAMPLERBUFFER USAMPLERBUFFER
+%token SAMPLER2DMS ISAMPLER2DMS USAMPLER2DMS
+%token SAMPLER2DMSARRAY ISAMPLER2DMSARRAY USAMPLER2DMSARRAY
 %token SAMPLEREXTERNALOES
 %token STRUCT VOID_TOK WHILE
 %token <identifier> IDENTIFIER TYPE_IDENTIFIER NEW_IDENTIFIER
 %type <identifier> any_identifier
+%type <interface_block> instance_name_opt
 %token <real> FLOATCONSTANT
 %token <n> INTCONSTANT UINTCONSTANT BOOLCONSTANT
 %token <identifier> FIELD_SELECTION
@@ -138,8 +142,7 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg)
 %token SAMPLER3DRECT
 %token SIZEOF CAST NAMESPACE USING
 %token COHERENT RESTRICT READONLY WRITEONLY RESOURCE ATOMIC_UINT PATCH SAMPLE
-%token SUBROUTINE SAMPLER2DMS ISAMPLER2DMS USAMPLER2DMS SAMPLER2DMSARRAY
-%token ISAMPLER2DMSARRAY USAMPLER2DMSARRAY
+%token SUBROUTINE
 
 %token ERROR_TOK
 
@@ -161,7 +164,8 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg)
 %type <type_qualifier> interpolation_qualifier
 %type <type_qualifier> layout_qualifier
 %type <type_qualifier> layout_qualifier_id_list layout_qualifier_id
-%type <type_qualifier> uniform_block_layout_qualifier
+%type <type_qualifier> interface_block_layout_qualifier
+%type <type_qualifier> interface_qualifier
 %type <type_specifier> type_specifier
 %type <type_specifier> type_specifier_no_prec
 %type <type_specifier> type_specifier_nonarray
@@ -217,10 +221,12 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg)
 %type <declarator_list> init_declarator_list
 %type <declarator_list> single_declaration
 %type <expression> initializer
+%type <expression> initializer_list
 %type <node> declaration
 %type <node> declaration_statement
 %type <node> jump_statement
-%type <node> uniform_block
+%type <node> interface_block
+%type <interface_block> basic_interface_block
 %type <struct_specifier> struct_specifier
 %type <declarator_list> struct_declaration_list
 %type <declarator_list> struct_declaration
@@ -262,10 +268,16 @@ version_statement:
        | VERSION_TOK INTCONSTANT EOL
        {
            state->process_version_directive(&@2, $2, NULL);
+          if (state->error) {
+             YYERROR;
+          }
        }
         | VERSION_TOK INTCONSTANT any_identifier EOL
         {
            state->process_version_directive(&@2, $2, $3);
+          if (state->error) {
+             YYERROR;
+          }
         }
        ;
 
@@ -780,7 +792,7 @@ declaration:
           $3->is_precision_statement = true;
           $$ = $3;
        }
-       | uniform_block
+       | interface_block
        {
           $$ = $1;
        }
@@ -950,6 +962,11 @@ init_declarator_list:
           $$ = $1;
           $$->declarations.push_tail(&decl->link);
           state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto));
+          if ($7->oper == ast_aggregate) {
+             ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$7;
+             ast_type_specifier *type = new(ctx) ast_type_specifier($1->type->specifier, true, NULL);
+             _mesa_ast_set_aggregate_type(type, ai, state);
+          }
        }
        | init_declarator_list ',' any_identifier '[' constant_expression ']' '=' initializer
        {
@@ -960,6 +977,11 @@ init_declarator_list:
           $$ = $1;
           $$->declarations.push_tail(&decl->link);
           state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto));
+          if ($8->oper == ast_aggregate) {
+             ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$8;
+             ast_type_specifier *type = new(ctx) ast_type_specifier($1->type->specifier, true, $5);
+             _mesa_ast_set_aggregate_type(type, ai, state);
+          }
        }
        | init_declarator_list ',' any_identifier '=' initializer
        {
@@ -970,6 +992,10 @@ init_declarator_list:
           $$ = $1;
           $$->declarations.push_tail(&decl->link);
           state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto));
+          if ($5->oper == ast_aggregate) {
+             ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$5;
+             _mesa_ast_set_aggregate_type($1->type->specifier, ai, state);
+          }
        }
        ;
 
@@ -1017,6 +1043,11 @@ single_declaration:
           $$ = new(ctx) ast_declarator_list($1);
           $$->set_location(yylloc);
           $$->declarations.push_tail(&decl->link);
+          if ($6->oper == ast_aggregate) {
+             ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$6;
+             ast_type_specifier *type = new(ctx) ast_type_specifier($1->specifier, true, NULL);
+             _mesa_ast_set_aggregate_type(type, ai, state);
+          }
        }
        | fully_specified_type any_identifier '[' constant_expression ']' '=' initializer
        {
@@ -1026,6 +1057,11 @@ single_declaration:
           $$ = new(ctx) ast_declarator_list($1);
           $$->set_location(yylloc);
           $$->declarations.push_tail(&decl->link);
+          if ($7->oper == ast_aggregate) {
+             ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$7;
+             ast_type_specifier *type = new(ctx) ast_type_specifier($1->specifier, true, $4);
+             _mesa_ast_set_aggregate_type(type, ai, state);
+          }
        }
        | fully_specified_type any_identifier '=' initializer
        {
@@ -1035,6 +1071,9 @@ single_declaration:
           $$ = new(ctx) ast_declarator_list($1);
           $$->set_location(yylloc);
           $$->declarations.push_tail(&decl->link);
+          if ($4->oper == ast_aggregate) {
+              _mesa_ast_set_aggregate_type($1->specifier, $4, state);
+          }
        }
        | INVARIANT variable_identifier // Vertex only.
        {
@@ -1088,6 +1127,7 @@ layout_qualifier_id_list:
 integer_constant:
        INTCONSTANT { $$ = $1; }
        | UINTCONSTANT { $$ = $1; }
+       ;
 
 layout_qualifier_id:
        any_identifier
@@ -1135,7 +1175,7 @@ layout_qualifier_id:
              }
           }
 
-          /* See also uniform_block_layout_qualifier. */
+          /* See also interface_block_layout_qualifier. */
           if (!$$.flags.i && state->ARB_uniform_buffer_object_enable) {
              if (strcmp($1, "std140") == 0) {
                 $$.flags.q.std140 = 1;
@@ -1143,6 +1183,12 @@ layout_qualifier_id:
                 $$.flags.q.shared = 1;
              } else if (strcmp($1, "column_major") == 0) {
                 $$.flags.q.column_major = 1;
+             /* "row_major" is a reserved word in GLSL 1.30+. Its token is parsed
+              * below in the interface_block_layout_qualifier rule.
+              *
+              * It is not a reserved word in GLSL ES 3.00, so it's handled here as
+              * an identifier.
+              */
              } else if (strcmp($1, "row_major") == 0) {
                 $$.flags.q.row_major = 1;
              }
@@ -1165,9 +1211,6 @@ layout_qualifier_id:
           memset(& $$, 0, sizeof($$));
 
           if (state->ARB_explicit_attrib_location_enable) {
-             /* FINISHME: Handle 'index' once GL_ARB_blend_func_exteneded and
-              * FINISHME: GLSL 1.30 (or later) are supported.
-              */
              if (strcmp("location", $1) == 0) {
                 $$.flags.q.explicit_location = 1;
 
@@ -1206,15 +1249,15 @@ layout_qualifier_id:
                                 "identifier `%s' used\n", $1);
           }
        }
-       | uniform_block_layout_qualifier
+       | interface_block_layout_qualifier
        {
           $$ = $1;
           /* Layout qualifiers for ARB_uniform_buffer_object. */
-          if (!state->ARB_uniform_buffer_object_enable) {
+          if ($$.flags.q.uniform && !state->ARB_uniform_buffer_object_enable) {
              _mesa_glsl_error(& @1, state,
                               "#version 140 / GL_ARB_uniform_buffer_object "
                               "layout qualifier `%s' is used\n", $1);
-          } else if (state->ARB_uniform_buffer_object_warn) {
+          } else if ($$.flags.q.uniform && state->ARB_uniform_buffer_object_warn) {
              _mesa_glsl_warning(& @1, state,
                                 "#version 140 / GL_ARB_uniform_buffer_object "
                                 "layout qualifier `%s' is used\n", $1);
@@ -1227,7 +1270,7 @@ layout_qualifier_id:
  * most qualifiers.  See the any_identifier path of
  * layout_qualifier_id for the others.
  */
-uniform_block_layout_qualifier:
+interface_block_layout_qualifier:
        ROW_MAJOR
        {
           memset(& $$, 0, sizeof($$));
@@ -1458,6 +1501,12 @@ basic_type_specifier_nonarray:
        | USAMPLER2DARRAY       { $$ = "usampler2DArray"; }
        | USAMPLERBUFFER        { $$ = "usamplerBuffer"; }
        | USAMPLERCUBEARRAY     { $$ = "usamplerCubeArray"; }
+       | SAMPLER2DMS           { $$ = "sampler2DMS"; }
+       | ISAMPLER2DMS          { $$ = "isampler2DMS"; }
+       | USAMPLER2DMS          { $$ = "usampler2DMS"; }
+       | SAMPLER2DMSARRAY      { $$ = "sampler2DMSArray"; }
+       | ISAMPLER2DMSARRAY     { $$ = "isampler2DMSArray"; }
+       | USAMPLER2DMSARRAY     { $$ = "usampler2DMSArray"; }
        ;
 
 precision_qualifier:
@@ -1485,6 +1534,7 @@ struct_specifier:
           $$ = new(ctx) ast_struct_specifier($2, $4);
           $$->set_location(yylloc);
           state->symbols->add_type($2, glsl_type::void_type);
+           state->symbols->add_type_ast($2, new(ctx) ast_type_specifier($$));
        }
        | STRUCT '{' struct_declaration_list '}'
        {
@@ -1541,7 +1591,6 @@ struct_declarator:
           void *ctx = state;
           $$ = new(ctx) ast_declaration($1, false, NULL, NULL);
           $$->set_location(yylloc);
-          state->symbols->add_variable(new(state) ir_variable(NULL, $1, ir_var_auto));
        }
        | any_identifier '[' constant_expression ']'
        {
@@ -1553,6 +1602,28 @@ struct_declarator:
 
 initializer:
        assignment_expression
+       | '{' initializer_list '}'
+       {
+          $$ = $2;
+       }
+       | '{' initializer_list ',' '}'
+       {
+          $$ = $2;
+       }
+       ;
+
+initializer_list:
+       initializer
+       {
+          void *ctx = state;
+          $$ = new(ctx) ast_aggregate_initializer();
+          $$->set_location(yylloc);
+          $$->expressions.push_tail(& $1->link);
+       }
+       | initializer_list ',' initializer
+       {
+          $1->expressions.push_tail(& $3->link);
+       }
        ;
 
 declaration_statement:
@@ -1883,42 +1954,163 @@ function_definition:
        ;
 
 /* layout_qualifieropt is packed into this rule */
-uniform_block:
-       UNIFORM NEW_IDENTIFIER '{' member_list '}' ';'
+interface_block:
+       basic_interface_block
        {
-          void *ctx = state;
-          $$ = new(ctx) ast_uniform_block(*state->default_uniform_qualifier,
-                                          $2, $4);
-
-          if (!state->ARB_uniform_buffer_object_enable) {
-             _mesa_glsl_error(& @1, state,
-                              "#version 140 / GL_ARB_uniform_buffer_object "
-                              "required for defining uniform blocks\n");
-          } else if (state->ARB_uniform_buffer_object_warn) {
-             _mesa_glsl_warning(& @1, state,
-                                "#version 140 / GL_ARB_uniform_buffer_object "
-                                "required for defining uniform blocks\n");
+          $$ = $1;
+       }
+       | layout_qualifier basic_interface_block
+       {
+          ast_interface_block *block = $2;
+          if (!block->layout.merge_qualifier(& @1, state, $1)) {
+             YYERROR;
           }
+          $$ = block;
        }
-       | layout_qualifier UNIFORM NEW_IDENTIFIER '{' member_list '}' ';'
+       ;
+
+basic_interface_block:
+       interface_qualifier NEW_IDENTIFIER '{' member_list '}' instance_name_opt ';'
        {
-          void *ctx = state;
+          ast_interface_block *const block = $6;
 
-          ast_type_qualifier qual = *state->default_uniform_qualifier;
-          if (!qual.merge_qualifier(& @1, state, $1)) {
-             YYERROR;
+          block->block_name = $2;
+          block->declarations.push_degenerate_list_at_head(& $4->link);
+
+          if ($1.flags.q.uniform) {
+             if (!state->ARB_uniform_buffer_object_enable) {
+                _mesa_glsl_error(& @1, state,
+                                 "#version 140 / GL_ARB_uniform_buffer_object "
+                                 "required for defining uniform blocks\n");
+             } else if (state->ARB_uniform_buffer_object_warn) {
+                _mesa_glsl_warning(& @1, state,
+                                   "#version 140 / GL_ARB_uniform_buffer_object "
+                                   "required for defining uniform blocks\n");
+             }
+          } else {
+             if (state->es_shader || state->language_version < 150) {
+                _mesa_glsl_error(& @1, state,
+                                "#version 150 required for using "
+                                "interface blocks.\n");
+             }
           }
-          $$ = new(ctx) ast_uniform_block(qual, $3, $5);
 
-          if (!state->ARB_uniform_buffer_object_enable) {
+          /* From the GLSL 1.50.11 spec, section 4.3.7 ("Interface Blocks"):
+           * "It is illegal to have an input block in a vertex shader
+           *  or an output block in a fragment shader"
+           */
+          if ((state->target == vertex_shader) && $1.flags.q.in) {
              _mesa_glsl_error(& @1, state,
-                              "#version 140 / GL_ARB_uniform_buffer_object "
-                              "required for defining uniform blocks\n");
-          } else if (state->ARB_uniform_buffer_object_warn) {
-             _mesa_glsl_warning(& @1, state,
-                                "#version 140 / GL_ARB_uniform_buffer_object "
-                                "required for defining uniform blocks\n");
+                              "`in' interface block is not allowed for "
+                              "a vertex shader\n");
+          } else if ((state->target == fragment_shader) && $1.flags.q.out) {
+             _mesa_glsl_error(& @1, state,
+                              "`out' interface block is not allowed for "
+                              "a fragment shader\n");
           }
+
+          /* Since block arrays require names, and both features are added in
+           * the same language versions, we don't have to explicitly
+           * version-check both things.
+           */
+          if (block->instance_name != NULL) {
+             state->check_version(150, 300, & @1, "interface blocks with "
+                       "an instance name are not allowed");
+          }
+
+          unsigned interface_type_mask;
+          struct ast_type_qualifier temp_type_qualifier;
+
+       /* Get a bitmask containing only the in/out/uniform flags, allowing us
+        * to ignore other irrelevant flags like interpolation qualifiers.
+        */
+          temp_type_qualifier.flags.i = 0;
+          temp_type_qualifier.flags.q.uniform = true;
+          temp_type_qualifier.flags.q.in = true;
+          temp_type_qualifier.flags.q.out = true;
+          interface_type_mask = temp_type_qualifier.flags.i;
+
+       /* Get the block's interface qualifier.  The interface_qualifier
+        * production rule guarantees that only one bit will be set (and
+        * it will be in/out/uniform).
+        */
+       unsigned block_interface_qualifier = $1.flags.i;
+
+          block->layout.flags.i |= block_interface_qualifier;
+
+          foreach_list_typed (ast_declarator_list, member, link, &block->declarations) {
+             ast_type_qualifier& qualifier = member->type->qualifier;
+             if ((qualifier.flags.i & interface_type_mask) == 0) {
+             /* GLSLangSpec.1.50.11, 4.3.7 (Interface Blocks):
+              * "If no optional qualifier is used in a member declaration, the
+              *  qualifier of the variable is just in, out, or uniform as declared
+              *  by interface-qualifier."
+              */
+                qualifier.flags.i |= block_interface_qualifier;
+             } else if ((qualifier.flags.i & interface_type_mask) !=
+                        block_interface_qualifier) {
+                /* GLSLangSpec.1.50.11, 4.3.7 (Interface Blocks):
+              * "If optional qualifiers are used, they can include interpolation
+              *  and storage qualifiers and they must declare an input, output,
+              *  or uniform variable consistent with the interface qualifier of
+              *  the block."
+                 */
+                _mesa_glsl_error(& @1, state,
+                                 "uniform/in/out qualifier on "
+                                 "interface block member does not match "
+                                 "the interface block\n");
+             }
+          }
+
+          $$ = block;
+       }
+       ;
+
+interface_qualifier:
+       IN_TOK
+       {
+          memset(& $$, 0, sizeof($$));
+          $$.flags.q.in = 1;
+       }
+       | OUT_TOK
+       {
+          memset(& $$, 0, sizeof($$));
+          $$.flags.q.out = 1;
+       }
+       | UNIFORM
+       {
+          memset(& $$, 0, sizeof($$));
+          $$.flags.q.uniform = 1;
+       }
+       ;
+
+instance_name_opt:
+       /* empty */
+       {
+          $$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
+                                            NULL,
+                                            NULL);
+       }
+       | NEW_IDENTIFIER
+       {
+          $$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
+                                            $1,
+                                            NULL);
+       }
+       | NEW_IDENTIFIER '[' constant_expression ']'
+       {
+          $$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
+                                            $1,
+                                            $3);
+       }
+       | NEW_IDENTIFIER '[' ']'
+       {
+          _mesa_glsl_error(& @1, state,
+                           "instance block arrays must be explicitly sized\n");
+
+          $$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
+                                            $1,
+                                            NULL);
        }
        ;
 
@@ -1935,41 +2127,28 @@ member_list:
        }
        ;
 
-/* Specifying "uniform" inside of a uniform block is redundant. */
-uniformopt:
-       /* nothing */
-       | UNIFORM
-       ;
-
 member_declaration:
-       layout_qualifier uniformopt type_specifier struct_declarator_list ';'
+       fully_specified_type struct_declarator_list ';'
        {
           void *ctx = state;
-          ast_fully_specified_type *type = new(ctx) ast_fully_specified_type();
+          ast_fully_specified_type *type = $1;
           type->set_location(yylloc);
 
-          type->qualifier = $1;
-          type->qualifier.flags.q.uniform = true;
-          type->specifier = $3;
-          $$ = new(ctx) ast_declarator_list(type);
-          $$->set_location(yylloc);
-          $$->ubo_qualifiers_valid = true;
-
-          $$->declarations.push_degenerate_list_at_head(& $4->link);
-       }
-       | uniformopt type_specifier struct_declarator_list ';'
-       {
-          void *ctx = state;
-          ast_fully_specified_type *type = new(ctx) ast_fully_specified_type();
-          type->set_location(yylloc);
+          if (type->qualifier.flags.q.attribute) {
+             _mesa_glsl_error(& @1, state,
+                             "keyword 'attribute' cannot be used with "
+                             "interface block member\n");
+          } else if (type->qualifier.flags.q.varying) {
+             _mesa_glsl_error(& @1, state,
+                             "keyword 'varying' cannot be used with "
+                             "interface block member\n");
+          }
 
-          type->qualifier.flags.q.uniform = true;
-          type->specifier = $2;
           $$ = new(ctx) ast_declarator_list(type);
           $$->set_location(yylloc);
           $$->ubo_qualifiers_valid = true;
 
-          $$->declarations.push_degenerate_list_at_head(& $3->link);
+          $$->declarations.push_degenerate_list_at_head(& $2->link);
        }
        ;