From 854fe24786be7d9753b989030b232fbdace34ccb Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Thu, 2 Mar 2017 14:30:59 -0700 Subject: [PATCH] HLSL: Fix #747: accept 'struct' in front of previously user-defined type name. --- Test/baseResults/hlsl.structStructName.frag.out | 84 +++++++++++++++++++++++++ Test/hlsl.structStructName.frag | 7 +++ glslang/Include/revision.h | 4 +- gtests/Hlsl.FromFile.cpp | 1 + hlsl/hlslGrammar.cpp | 52 +++++++++------ hlsl/hlslGrammar.h | 2 +- hlsl/hlslParseHelper.cpp | 13 ++++ hlsl/hlslParseHelper.h | 1 + 8 files changed, 143 insertions(+), 21 deletions(-) create mode 100755 Test/baseResults/hlsl.structStructName.frag.out create mode 100755 Test/hlsl.structStructName.frag diff --git a/Test/baseResults/hlsl.structStructName.frag.out b/Test/baseResults/hlsl.structStructName.frag.out new file mode 100755 index 0000000..da4c400 --- /dev/null +++ b/Test/baseResults/hlsl.structStructName.frag.out @@ -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 diff --git a/Test/hlsl.structStructName.frag b/Test/hlsl.structStructName.frag new file mode 100755 index 0000000..f8bf90c --- /dev/null +++ b/Test/hlsl.structStructName.frag @@ -0,0 +1,7 @@ +struct S { int s; }; + +int main() +{ + struct S t; + return t.s; +} diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h index 7359459..e9fc7fe 100644 --- a/glslang/Include/revision.h +++ b/glslang/Include/revision.h @@ -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" diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index d523231..689a015 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -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"}, diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp index 9b3a5fa..86a3267 100755 --- a/hlsl/hlslGrammar.cpp +++ b/hlsl/hlslGrammar.cpp @@ -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 diff --git a/hlsl/hlslGrammar.h b/hlsl/hlslGrammar.h index c8753fd..07080e4 100755 --- a/hlsl/hlslGrammar.h +++ b/hlsl/hlslGrammar.h @@ -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 diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index 5ae9e74..65a99f8 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -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 diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h index e718f40..5b585dc 100755 --- a/hlsl/hlslParseHelper.h +++ b/hlsl/hlslParseHelper.h @@ -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&); -- 2.7.4