浏览代码

[ATOM-4800] Unclear Error Message for Function Inside Struct (#6)

In order to catch the error of function inside struct
it was necessary to modify the grammar to allow function definitions
and declarations inside "struct" definitions (just like classes,
interfaces and ShaderResourceGroups), this way
the ANTLR parser would let it pass, giving the chance for AZSLc
to provide a meaningful error message.

ANTLR Syntax Error message:
"no viable alternative at input
structParallaxMapping{Texture2Dm_depthMap;floatm_depthFactor;boolm_isHeightmap;floatm_parallaxShadowFactor;float2GetParallaxUV("

New AZSLc produced Error message:
"function_declared_in_struct.azsl(14,4) : Syntax error #516: structs
cannot have member functions; consider using a class."

Signed-off-by: garrieta <[email protected]>
galibzon 4 年之前
父节点
当前提交
5e809f4c60

+ 1 - 0
src/AzslcException.h

@@ -100,6 +100,7 @@ namespace AZ::ShaderCompiler
         ADVANCED_SYNTAX_CONSTANT_BUFFER_ONLY_IN_SRG = 513u,
         ADVANCED_SYNTAX_CONSTANT_BUFFER_ONLY_IN_SRG = 513u,
         ADVANCED_SYNTAX_DOUBLE_SCOPE_RESOLUTION = 514u,
         ADVANCED_SYNTAX_DOUBLE_SCOPE_RESOLUTION = 514u,
         ADVANCED_RESERVED_NAME_USED = 515u,
         ADVANCED_RESERVED_NAME_USED = 515u,
+        ADVANCED_SYNTAX_FUNCTION_IN_STRUCT = 516u,
     };
     };
 
 
     class AzslcException : public antlr4::RuntimeException
     class AzslcException : public antlr4::RuntimeException

+ 18 - 0
src/AzslcListener.cpp

@@ -196,6 +196,15 @@ namespace AZ::ShaderCompiler
 
 
     void SemaCheckListener::enterFunctionDefinition(azslParser::FunctionDefinitionContext* ctx)
     void SemaCheckListener::enterFunctionDefinition(azslParser::FunctionDefinitionContext* ctx)
     {
     {
+        // Forbid function definitions inside "struct"s.
+        if (m_ir->m_sema.IsScopeStruct())
+        {
+            throw AzslcException(ADVANCED_SYNTAX_FUNCTION_IN_STRUCT,
+                                 "Syntax",
+                                 ctx->start,
+                                 "structs cannot have member functions; consider using a class.");
+        }
+
         auto signature = ctx->hlslFunctionDefinition()->leadingTypeFunctionSignature();
         auto signature = ctx->hlslFunctionDefinition()->leadingTypeFunctionSignature();
         auto uqName = ExtractNameFromAnyContextWithName(signature);
         auto uqName = ExtractNameFromAnyContextWithName(signature);
 
 
@@ -226,6 +235,15 @@ namespace AZ::ShaderCompiler
 
 
     void SemaCheckListener::enterFunctionDeclaration(azslParser::FunctionDeclarationContext* ctx)
     void SemaCheckListener::enterFunctionDeclaration(azslParser::FunctionDeclarationContext* ctx)
     {
     {
+        // Forbid function declarations inside "struct"s.
+        if (m_ir->m_sema.IsScopeStruct())
+        {
+            throw AzslcException(ADVANCED_SYNTAX_FUNCTION_IN_STRUCT,
+                                 "Syntax",
+                                 ctx->start,
+                                 "structs cannot have member functions; consider using a class.");
+        }
+
         auto signature = ctx->hlslFunctionDeclaration()->leadingTypeFunctionSignature();
         auto signature = ctx->hlslFunctionDeclaration()->leadingTypeFunctionSignature();
         auto uqName = ExtractNameFromAnyContextWithName(signature);
         auto uqName = ExtractNameFromAnyContextWithName(signature);
         auto& [id, _] = m_ir->m_sema.RegisterFunctionDeclarationAndAddSeenat(uqName, signature);
         auto& [id, _] = m_ir->m_sema.RegisterFunctionDeclarationAndAddSeenat(uqName, signature);

+ 1 - 1
src/AzslcMain.cpp

@@ -23,7 +23,7 @@ namespace StdFs = std::filesystem;
 // For large features or milestones. Minor version allows for breaking changes. Existing tests can change.
 // For large features or milestones. Minor version allows for breaking changes. Existing tests can change.
 #define AZSLC_MINOR    "7"
 #define AZSLC_MINOR    "7"
 // For small features or bug fixes. They cannot introduce breaking changes. Existing tests shouldn't change.
 // For small features or bug fixes. They cannot introduce breaking changes. Existing tests shouldn't change.
-#define AZSLC_REVISION "27" // ATOM-2430
+#define AZSLC_REVISION "28" // ATOM-4800
 
 
 namespace AZ::ShaderCompiler
 namespace AZ::ShaderCompiler
 {
 {

+ 6 - 0
src/AzslcSemanticOrchestrator.cpp

@@ -1953,6 +1953,12 @@ namespace AZ::ShaderCompiler
         return found;
         return found;
     }
     }
 
 
+    bool SemanticOrchestrator::IsScopeStruct() const
+    {
+        const KindInfo& scopeKind = m_symbols->GetIdAndKindInfo(m_scope->GetNameOfCurScope())->second;
+        return scopeKind.IsKindOneOf(Kind::Struct);
+    }
+
     bool SemanticOrchestrator::IsScopeStructClassInterface() const
     bool SemanticOrchestrator::IsScopeStructClassInterface() const
     {
     {
         const KindInfo& scopeKind = m_symbols->GetIdAndKindInfo(m_scope->GetNameOfCurScope())->second;
         const KindInfo& scopeKind = m_symbols->GetIdAndKindInfo(m_scope->GetNameOfCurScope())->second;

+ 4 - 1
src/AzslcSemanticOrchestrator.h

@@ -351,9 +351,12 @@ namespace AZ::ShaderCompiler
         // another helper to streamline what to do directly with the result from ExtractTypeNameFromAstContext function families.
         // another helper to streamline what to do directly with the result from ExtractTypeNameFromAstContext function families.
         auto CreateExtendedTypeInfo(const ExtractedComposedType& extractedComposed, ArrayDimensions dims, Packing::MatrixMajor mtxMajor) const -> ExtendedTypeInfo;
         auto CreateExtendedTypeInfo(const ExtractedComposedType& extractedComposed, ArrayDimensions dims, Packing::MatrixMajor mtxMajor) const -> ExtendedTypeInfo;
 
 
-        //! check if current scope is a structured user defined type
+        //! check if current scope is a structured user defined type ("struct", "class" or "interface")
         bool IsScopeStructClassInterface() const;
         bool IsScopeStructClassInterface() const;
 
 
+        //! check if current scope is of type "struct".
+        bool IsScopeStruct() const;
+
         //! Find a concrete function from an overload-set and an argument list.
         //! Find a concrete function from an overload-set and an argument list.
         //! (adjust the shoot of a lookup to something more precise in case that it's possible)
         //! (adjust the shoot of a lookup to something more precise in case that it's possible)
         //! if maybeOverloadSet is not an overload-set the function returns identity
         //! if maybeOverloadSet is not an overload-set the function returns identity

+ 2 - 0
src/azslParser.g4

@@ -78,6 +78,8 @@ structDefinition:
 
 
 structMemberDeclaration:
 structMemberDeclaration:
         variableDeclarationStatement
         variableDeclarationStatement
+    |   attributedFunctionDefinition //AZSL+, forbidden, but allows us to provide better error message.
+    |   attributedFunctionDeclaration //AZSL+, forbidden, but allows us to provide better error message.
     |   anyStructuredTypeDefinitionStatement  // AZSL+
     |   anyStructuredTypeDefinitionStatement  // AZSL+
     |   typeAliasingDefinitionStatement // AZSL+
     |   typeAliasingDefinitionStatement // AZSL+
 ;
 ;

文件差异内容过多而无法显示
+ 202 - 179
src/generated/azslParser.cpp


+ 2 - 0
src/generated/azslParser.h

@@ -503,6 +503,8 @@ public:
     StructMemberDeclarationContext(antlr4::ParserRuleContext *parent, size_t invokingState);
     StructMemberDeclarationContext(antlr4::ParserRuleContext *parent, size_t invokingState);
     virtual size_t getRuleIndex() const override;
     virtual size_t getRuleIndex() const override;
     VariableDeclarationStatementContext *variableDeclarationStatement();
     VariableDeclarationStatementContext *variableDeclarationStatement();
+    AttributedFunctionDefinitionContext *attributedFunctionDefinition();
+    AttributedFunctionDeclarationContext *attributedFunctionDeclaration();
     AnyStructuredTypeDefinitionStatementContext *anyStructuredTypeDefinitionStatement();
     AnyStructuredTypeDefinitionStatementContext *anyStructuredTypeDefinitionStatement();
     TypeAliasingDefinitionStatementContext *typeAliasingDefinitionStatement();
     TypeAliasingDefinitionStatementContext *typeAliasingDefinitionStatement();
 
 

+ 26 - 0
tests/Samples/AsError/function_declared_in_struct.azsl

@@ -0,0 +1,26 @@
+// Syntax error of function declaration inside struct.
+// Syntax error #516: structs cannot have member functions; consider using a class.
+// #EC 516
+
+ShaderResourceGroupSemantic slot1
+{
+    FrequencyId = 1;
+};
+
+struct SomeStruct
+{
+    float4 m_color;
+
+    float4 GetColor();
+};
+
+ShaderResourceGroup DemoSrg : slot1
+{
+    SomeStruct m_data;
+};
+
+float4 MainPS() : SV_Target0
+{
+    float4 color = DemoSrg::m_data.GetColor();
+    return color;
+}

+ 29 - 0
tests/Samples/AsError/function_defined_in_struct.azsl

@@ -0,0 +1,29 @@
+// Syntax error of function definition inside struct.
+// Syntax error #516: structs cannot have member functions; consider using a class.
+// #EC 516
+
+ShaderResourceGroupSemantic slot1
+{
+    FrequencyId = 1;
+};
+
+struct SomeStruct
+{
+    float4 m_color;
+
+    float4 GetColor()
+    {
+        return m_color;
+    }
+};
+
+ShaderResourceGroup DemoSrg : slot1
+{
+    SomeStruct m_data;
+};
+
+float4 MainPS() : SV_Target0
+{
+    float4 color = DemoSrg::m_data.GetColor();
+    return color;
+}

部分文件因为文件数量过多而无法显示