diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -190,6 +190,22 @@ } }; +class HLSLAnnotationAttr : public InheritableAttr { +protected: + HLSLAnnotationAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo, + attr::Kind AK, bool IsLateParsed, + bool InheritEvenIfAlreadyPresent) + : InheritableAttr(Context, CommonInfo, AK, IsLateParsed, + InheritEvenIfAlreadyPresent) {} + +public: + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() >= attr::FirstHLSLAnnotationAttr && + A->getKind() <= attr::LastHLSLAnnotationAttr; + } +}; + /// A parameter attribute which changes the argument-passing ABI rule /// for the parameter. class ParameterABIAttr : public InheritableParamAttr { diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -607,6 +607,9 @@ /// A attribute is either a declaration attribute or a statement attribute. class DeclOrStmtAttr : InheritableAttr; +/// An attribute class for HLSL Annotations. +class HLSLAnnotationAttr : InheritableAttr; + /// A target-specific attribute. This class is meant to be used as a mixin /// with InheritableAttr or Attr depending on the attribute's needs. class TargetSpecificAttr { @@ -4005,7 +4008,7 @@ let Documentation = [NumThreadsDocs]; } -def HLSLSV_GroupIndex: InheritableAttr { +def HLSLSV_GroupIndex: HLSLAnnotationAttr { let Spellings = [HLSLSemantic<"SV_GroupIndex">]; let Subjects = SubjectList<[ParmVar, GlobalVar]>; let LangOpts = [HLSL]; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11632,6 +11632,7 @@ def err_hlsl_numthreads_invalid : Error<"total number of threads cannot exceed %0">; def err_hlsl_missing_numthreads : Error<"missing numthreads attribute for %0 shader entry">; def err_hlsl_attribute_param_mismatch : Error<"%0 attribute parameters do not match the previous declaration">; +def err_hlsl_missing_semantic_annotation : Error<"semantic annotations must be present for all parameters of an entry function or patch constant function">; def err_hlsl_pointers_unsupported : Error< "%select{pointers|references}0 are unsupported in HLSL">; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -11870,6 +11870,15 @@ } break; } + + for (const auto *Param : FD->parameters()) { + if (!Param->hasAttr()) { + // FIXME: Handle struct parameters where annotations are on struct fields. + Diag(FD->getLocation(), diag::err_hlsl_missing_semantic_annotation); + Diag(Param->getLocation(), diag::note_previous_decl) << Param; + FD->setInvalidDecl(); + } + } } bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { diff --git a/clang/test/SemaHLSL/Semantics/missing_entry_annotation.hlsl b/clang/test/SemaHLSL/Semantics/missing_entry_annotation.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/SemaHLSL/Semantics/missing_entry_annotation.hlsl @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -fsyntax-only -hlsl-entry main -verify %s + +[numthreads(1,1, 1)] +void main(int GI) { } // expected-error{{semantic annotations must be present for all parameters of an entry function or patch constant function}} expected-note{{'GI' declared here}} diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -2852,7 +2852,8 @@ { "INHERITABLE_ATTR", "InheritableAttr" }, { "DECL_OR_TYPE_ATTR", "DeclOrTypeAttr" }, { "INHERITABLE_PARAM_ATTR", "InheritableParamAttr" }, - { "PARAMETER_ABI_ATTR", "ParameterABIAttr" } + { "PARAMETER_ABI_ATTR", "ParameterABIAttr" }, + { "HLSL_ANNOTATION_ATTR", "HLSLAnnotationAttr"} }; static void emitDefaultDefine(raw_ostream &OS, StringRef name,