HLSL: Fix #747: accept 'struct' in front of previously user-defined type name.

This commit is contained in:
John Kessenich 2017-03-02 14:30:59 -07:00
parent 0479437a5c
commit 854fe24786
8 changed files with 143 additions and 21 deletions

View File

@ -0,0 +1,84 @@
hlsl.structStructName.frag
Shader version: 450
gl_FragCoord origin is upper left
0:? Sequence
0:4 Function Definition: @main( (temp int)
0:4 Function Parameters:
0:? Sequence
0:6 Branch: Return with expression
0:6 s: direct index for structure (temp int)
0:6 't' (temp structure{temp int s})
0:6 Constant:
0:6 0 (const int)
0:4 Function Definition: main( (temp void)
0:4 Function Parameters:
0:? Sequence
0:4 move second child to first child (temp int)
0:? '@entryPointOutput' (layout(location=0 ) out int)
0:4 Function Call: @main( (temp int)
0:? Linker Objects
0:? '@entryPointOutput' (layout(location=0 ) out int)
Linked fragment stage:
Shader version: 450
gl_FragCoord origin is upper left
0:? Sequence
0:4 Function Definition: @main( (temp int)
0:4 Function Parameters:
0:? Sequence
0:6 Branch: Return with expression
0:6 s: direct index for structure (temp int)
0:6 't' (temp structure{temp int s})
0:6 Constant:
0:6 0 (const int)
0:4 Function Definition: main( (temp void)
0:4 Function Parameters:
0:? Sequence
0:4 move second child to first child (temp int)
0:? '@entryPointOutput' (layout(location=0 ) out int)
0:4 Function Call: @main( (temp int)
0:? Linker Objects
0:? '@entryPointOutput' (layout(location=0 ) out int)
// Module Version 10000
// Generated by (magic number): 80001
// Id's are bound by 22
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Fragment 4 "main" 20
ExecutionMode 4 OriginUpperLeft
Name 4 "main"
Name 8 "@main("
Name 10 "S"
MemberName 10(S) 0 "s"
Name 12 "t"
Name 20 "@entryPointOutput"
Decorate 20(@entryPointOutput) Location 0
2: TypeVoid
3: TypeFunction 2
6: TypeInt 32 1
7: TypeFunction 6(int)
10(S): TypeStruct 6(int)
11: TypePointer Function 10(S)
13: 6(int) Constant 0
14: TypePointer Function 6(int)
19: TypePointer Output 6(int)
20(@entryPointOutput): 19(ptr) Variable Output
4(main): 2 Function None 3
5: Label
21: 6(int) FunctionCall 8(@main()
Store 20(@entryPointOutput) 21
Return
FunctionEnd
8(@main(): 6(int) Function None 7
9: Label
12(t): 11(ptr) Variable Function
15: 14(ptr) AccessChain 12(t) 13
16: 6(int) Load 15
ReturnValue 16
FunctionEnd

View File

@ -0,0 +1,7 @@
struct S { int s; };
int main()
{
struct S t;
return t.s;
}

View File

@ -2,5 +2,5 @@
// For the version, it uses the latest git tag followed by the number of commits.
// For the date, it uses the current date (when then script is run).
#define GLSLANG_REVISION "Overload400-PrecQual.1870"
#define GLSLANG_DATE "01-Mar-2017"
#define GLSLANG_REVISION "Overload400-PrecQual.1871"
#define GLSLANG_DATE "02-Mar-2017"

View File

@ -231,6 +231,7 @@ INSTANTIATE_TEST_CASE_P(
{"hlsl.structbuffer.rwbyte.frag", "main"},
{"hlsl.structin.vert", "main"},
{"hlsl.structIoFourWay.frag", "main"},
{"hlsl.structStructName.frag", "main"},
{"hlsl.intrinsics.vert", "VertexShaderFunction"},
{"hlsl.matType.frag", "PixelShaderFunction"},
{"hlsl.matType.bool.frag", "main"},

View File

@ -1268,9 +1268,8 @@ bool HlslGrammar::acceptType(TType& type)
// An identifier could be for a user-defined type.
// Note we cache the symbol table lookup, to save for a later rule
// when this is not a type.
token.symbol = parseContext.symbolTable.find(*token.string);
if (token.symbol && token.symbol->getAsVariable() && token.symbol->getAsVariable()->isUserType()) {
type.shallowCopy(token.symbol->getType());
token.symbol = parseContext.lookupUserType(*token.string, type);
if (token.symbol != nullptr) {
advanceToken();
return true;
} else
@ -1729,6 +1728,7 @@ bool HlslGrammar::acceptType(TType& type)
// struct
// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
// | struct_type IDENTIFIER // use of previously declared struct type
//
// struct_type
// : STRUCT
@ -1761,12 +1761,18 @@ bool HlslGrammar::acceptStruct(TType& type)
// post_decls
TQualifier postDeclQualifier;
postDeclQualifier.clear();
acceptPostDecls(postDeclQualifier);
bool postDeclsFound = acceptPostDecls(postDeclQualifier);
// LEFT_BRACE
// struct_type IDENTIFIER
if (! acceptTokenClass(EHTokLeftBrace)) {
expected("{");
return false;
if (structName.size() > 0 && !postDeclsFound && parseContext.lookupUserType(structName, type) != nullptr) {
// struct_type IDENTIFIER
return true;
} else {
expected("{");
return false;
}
}
// struct_declaration_list
@ -3274,11 +3280,18 @@ void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes)
// COLON LAYOUT layout_qualifier_list
// annotations // optional
//
void HlslGrammar::acceptPostDecls(TQualifier& qualifier)
// Return true if any tokens were accepted. That is,
// false can be returned on successfully recognizing nothing,
// not necessarily meaning bad syntax.
//
bool HlslGrammar::acceptPostDecls(TQualifier& qualifier)
{
bool found = false;
do {
// COLON
if (acceptTokenClass(EHTokColon)) {
found = true;
HlslToken idToken;
if (peekTokenClass(EHTokLayout))
acceptLayoutQualifierList(qualifier);
@ -3286,18 +3299,18 @@ void HlslGrammar::acceptPostDecls(TQualifier& qualifier)
// PACKOFFSET LEFT_PAREN c[Subcomponent][.component] RIGHT_PAREN
if (! acceptTokenClass(EHTokLeftParen)) {
expected("(");
return;
return false;
}
HlslToken locationToken;
if (! acceptIdentifier(locationToken)) {
expected("c[subcomponent][.component]");
return;
return false;
}
HlslToken componentToken;
if (acceptTokenClass(EHTokDot)) {
if (! acceptIdentifier(componentToken)) {
expected("component");
return;
return false;
}
}
if (! acceptTokenClass(EHTokRightParen)) {
@ -3307,19 +3320,19 @@ void HlslGrammar::acceptPostDecls(TQualifier& qualifier)
parseContext.handlePackOffset(locationToken.loc, qualifier, *locationToken.string, componentToken.string);
} else if (! acceptIdentifier(idToken)) {
expected("layout, semantic, packoffset, or register");
return;
return false;
} else if (*idToken.string == "register") {
// REGISTER LEFT_PAREN [shader_profile,] Type#[subcomp]opt (COMMA SPACEN)opt RIGHT_PAREN
// LEFT_PAREN
if (! acceptTokenClass(EHTokLeftParen)) {
expected("(");
return;
return false;
}
HlslToken registerDesc; // for Type#
HlslToken profile;
if (! acceptIdentifier(registerDesc)) {
expected("register number description");
return;
return false;
}
if (registerDesc.string->size() > 1 && !isdigit((*registerDesc.string)[1]) &&
acceptTokenClass(EHTokComma)) {
@ -3328,7 +3341,7 @@ void HlslGrammar::acceptPostDecls(TQualifier& qualifier)
profile = registerDesc;
if (! acceptIdentifier(registerDesc)) {
expected("register number description");
return;
return false;
}
}
int subComponent = 0;
@ -3336,7 +3349,7 @@ void HlslGrammar::acceptPostDecls(TQualifier& qualifier)
// LEFT_BRACKET subcomponent RIGHT_BRACKET
if (! peekTokenClass(EHTokIntConstant)) {
expected("literal integer");
return;
return false;
}
subComponent = token.i;
advanceToken();
@ -3350,7 +3363,7 @@ void HlslGrammar::acceptPostDecls(TQualifier& qualifier)
if (acceptTokenClass(EHTokComma)) {
if (! acceptIdentifier(spaceDesc)) {
expected ("space identifier");
return;
return false;
}
}
// RIGHT_PAREN
@ -3363,12 +3376,15 @@ void HlslGrammar::acceptPostDecls(TQualifier& qualifier)
// semantic, in idToken.string
parseContext.handleSemantic(idToken.loc, qualifier, *idToken.string);
}
} else if (peekTokenClass(EHTokLeftAngle))
} else if (peekTokenClass(EHTokLeftAngle)) {
found = true;
acceptAnnotations(qualifier);
else
} else
break;
} while (true);
return found;
}
} // end namespace glslang

View File

@ -114,7 +114,7 @@ namespace glslang {
bool acceptCaseLabel(TIntermNode*&);
bool acceptDefaultLabel(TIntermNode*&);
void acceptArraySpecifier(TArraySizes*&);
void acceptPostDecls(TQualifier&);
bool acceptPostDecls(TQualifier&);
bool acceptDefaultParameterDeclaration(const TType&, TIntermTyped*&);
HlslParseContext& parseContext; // state of parsing and helper functions for building the intermediate

View File

@ -6098,6 +6098,19 @@ void HlslParseContext::declareStruct(const TSourceLoc& loc, TString& structName,
ioTypeMap[type.getStruct()] = newLists;
}
// Lookup a user-type by name.
// If found, fill in the type and return the defining symbol.
// If not found, return nullptr.
TSymbol* HlslParseContext::lookupUserType(const TString& typeName, TType& type)
{
TSymbol* symbol = symbolTable.find(typeName);
if (symbol && symbol->getAsVariable() && symbol->getAsVariable()->isUserType()) {
type.shallowCopy(symbol->getType());
return symbol;
} else
return nullptr;
}
//
// Do everything necessary to handle a variable (non-block) declaration.
// Either redeclaring a variable, or making a new one, updating the symbol

View File

@ -133,6 +133,7 @@ public:
const TFunction* findFunction(const TSourceLoc& loc, TFunction& call, bool& builtIn, TIntermTyped*& args);
void declareTypedef(const TSourceLoc&, TString& identifier, const TType&);
void declareStruct(const TSourceLoc&, TString& structName, TType&);
TSymbol* lookupUserType(const TString&, TType&);
TIntermNode* declareVariable(const TSourceLoc&, TString& identifier, TType&, TIntermTyped* initializer = 0);
void lengthenList(const TSourceLoc&, TIntermSequence& list, int size);
TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&);