diff options
| author | Ellie Hermaszewska <ellieh@nvidia.com> | 2023-04-17 22:22:13 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-04-17 22:22:13 +0800 |
| commit | a3f622ace1bdef1f1a4150ec85d1328d1a589333 (patch) | |
| tree | c1c620d0e69d39870fdbc76f5e584bae8594f0ba | |
| parent | f6ff73fe3156215e75708d155fd240788134b1f2 (diff) | |
WIP: "deprecated" attribute (#2698)
* Implement deprecated attribute
* Prevent duplicate deprecated diagnostic on non-overloaded functions
* Use FileCheck for deprecation test
* formatting
| -rw-r--r-- | source/slang/core.meta.slang | 3 | ||||
| -rw-r--r-- | source/slang/hlsl.meta.slang | 2 | ||||
| -rw-r--r-- | source/slang/slang-ast-modifier.h | 12 | ||||
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 41 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 3 | ||||
| -rw-r--r-- | source/slang/slang-check-modifier.cpp | 12 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 2 | ||||
| -rw-r--r-- | tests/diagnostics/deprecation.slang | 60 |
8 files changed, 133 insertions, 2 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 3f1e99880..849e4c642 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -3129,3 +3129,6 @@ attribute_syntax [noinline] : NoInlineAttribute; __attributeTarget(StructDecl) attribute_syntax [payload] : PayloadAttribute; + +__attributeTarget(DeclBase) +attribute_syntax [deprecated(message: String)] : DeprecatedAttribute; diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 8ad99d71b..a47c0cb25 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -3140,12 +3140,14 @@ matrix<T,R,C> mul(matrix<T,R,N> right, matrix<T,N,C> left) // noise (deprecated) [__readNone] +[deprecated("Always returns 0")] float noise(float x) { return 0; } [__readNone] +[deprecated("Always returns 0")] __generic<let N : int> float noise(vector<float, N> x) { return 0; diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index 0b077477d..caa439704 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -1256,6 +1256,18 @@ class PayloadAttribute : public Attribute SLANG_AST_CLASS(PayloadAttribute) }; + /// A `[deprecated("message")]` attribute indicates the target is + /// deprecated. + /// A compiler warning including the message will be raised if the + /// deprecated value is used. + /// +class DeprecatedAttribute : public Attribute +{ + SLANG_AST_CLASS(DeprecatedAttribute) + + String message; +}; + /// A modifier that applies to types rather than declarations. /// /// In most cases, the Slang compiler assumes that a modifier should diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 507b8c30f..119077eca 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -254,7 +254,42 @@ namespace Slang return SourceLoc(); } - Expr* SemanticsVisitor::ConstructDeclRefExpr( + void SemanticsVisitor::diagnoseDeprecatedDeclRefUsage( + DeclRef<Decl> declRef, + SourceLoc loc, + Expr* originalExpr) + { + // This is slightly subtle, because we don't want to warn more than + // once for the same occurrence, however in some cases this function is + // called more than once for the same declref (specifically in the case + // of a non-overloaded function, once when the function is identified at + // first, and again when it's checked from + // CheckInvokeExprWithCheckedOperands). + // + // The correct fix is probably to make + // CheckInvokeExprWithCheckedOperands reuse the original declref, + // however that doesn't appear to be a simple change. + // + // What we do instead is see if there's already been a declRef + // constructed for this expression and rest assured that it's already + // had a diagnostic emitted. + auto originalAppExpr = as<AppExprBase>(originalExpr); + auto originalAppFunDecl = originalAppExpr ? as<DeclRefExpr>(originalAppExpr->functionExpr) : nullptr; + if(originalAppFunDecl && originalAppFunDecl->declRef) + { + return; + } + if (auto deprecatedAttr = declRef.getDecl()->findModifier<DeprecatedAttribute>()) + { + getSink()->diagnose( + loc, + Diagnostics::deprecatedUsage, + declRef.getName(), + deprecatedAttr->message); + } + } + + DeclRefExpr* SemanticsVisitor::ConstructDeclRefExpr( DeclRef<Decl> declRef, Expr* baseExpr, SourceLoc loc, @@ -264,6 +299,10 @@ namespace Slang // auto type = GetTypeForDeclRef(declRef, loc); + // This is the bottleneck for using declarations which might be + // deprecated, diagnose here. + diagnoseDeprecatedDeclRefUsage(declRef, loc, originalExpr); + // Construct an appropriate expression based on the structured of // the declaration reference. // diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 18a60b8b3..b4a779a66 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -575,8 +575,9 @@ namespace Slang /// If `expr` has Ref<T> Type, convert it into an l-value expr that has T type. Expr* maybeOpenRef(Expr* expr); + void diagnoseDeprecatedDeclRefUsage(DeclRef<Decl> declRef, SourceLoc loc, Expr* originalExpr); - Expr* ConstructDeclRefExpr( + DeclRefExpr* ConstructDeclRefExpr( DeclRef<Decl> declRef, Expr* baseExpr, SourceLoc loc, diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp index d96d9e39e..e5627850b 100644 --- a/source/slang/slang-check-modifier.cpp +++ b/source/slang/slang-check-modifier.cpp @@ -713,6 +713,18 @@ namespace Slang return false; } } + else if (auto deprecatedAttr = as<DeprecatedAttribute>(attr)) + { + SLANG_ASSERT(attr->args.getCount() == 1); + + String message; + if(!checkLiteralStringVal(attr->args[0], &message)) + { + return false; + } + + deprecatedAttr->message = message; + } else { if(attr->args.getCount() == 0) diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 80ba1f55b..130102e44 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -361,6 +361,8 @@ DIAGNOSTIC(31148, Error, cannotResolveDerivativeFunction, "cannot resolve the cu DIAGNOSTIC(31149, Error, differentiableGenericInterfaceMethodNotSupported, "`[ForwardDifferentiable] and [BackwardDifferentiable] are not supported on generic interface requirements.") +DIAGNOSTIC(31200, Warning, deprecatedUsage, "$0 has been deprecated: $1") + // Enums DIAGNOSTIC(32000, Error, invalidEnumTagType, "invalid tag type for 'enum': '$0'") diff --git a/tests/diagnostics/deprecation.slang b/tests/diagnostics/deprecation.slang new file mode 100644 index 000000000..75dfd51d8 --- /dev/null +++ b/tests/diagnostics/deprecation.slang @@ -0,0 +1,60 @@ +//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): + +// Here we test that diagnostics appear once per usage of each of the +// deprecated declarations. + +[deprecated("please use foo(bool)")] +void foo(int) {} + +void foo(bool) {} + +[deprecated("non-overloaded bar")] +void bar() {} + +const float newPi = 3.1; + +[deprecated("more precise approximations are available elsewhere")] +const int pi = 3; + +[deprecated("no")] +struct Billiards +{ + [deprecated("puns")] + bool bs[22]; +} + +int main() +{ + pi; + // CHECK: tests/diagnostics/deprecation.slang([[#@LINE-1]]): warning 31200: pi has been deprecated: more precise approximations are available elsewhere + // CHECK-NEXT: pi; + // CHECK-NEXT: ^~ + + foo(0); + // CHECK: tests/diagnostics/deprecation.slang([[#@LINE-1]]): warning 31200: foo has been deprecated: please use foo(bool) + // CHECK-NEXT: foo(0); + // CHECK-NEXT: ^~~ + + foo(false); // doesn't warn + // CHECK-NOT: tests/diagnostics/deprecation.slang([[#@LINE-1]]) + + Billiards b; + // CHECK: tests/diagnostics/deprecation.slang([[#@LINE-1]]): warning 31200: Billiards has been deprecated: no + // CHECK-NEXT: Billiards b; + // CHECK-NEXT: ^~~~~~~~~ + + b.bs; + // CHECK: tests/diagnostics/deprecation.slang([[#@LINE-1]]): warning 31200: bs has been deprecated: puns + // CHECK-NEXT: b.bs; + // CHECK-NEXT: ^~ + + bar(); + // CHECK: tests/diagnostics/deprecation.slang([[#@LINE-1]]): warning 31200: bar has been deprecated: non-overloaded bar + // CHECK-NEXT: bar(); + // CHECK-NEXT: ^~~ + + // Check we don't have any extra warnings not caught by the above diagnostics + // CHECK-NOT: warning + + return 0; +} |
