summary refs log tree commit diff stats
diff options
context:
space:
mode:
authormetagn <metagngn@gmail.com>2023-04-13 13:50:43 +0300
committerGitHub <noreply@github.com>2023-04-13 12:50:43 +0200
commitc694d8e4fd6a14ab6a79fe6359033a4be6133b8c (patch)
tree954b1115667abddf400921f245bd447d3cb90eef
parent16f42084d32144d5afb2a5cc3a5a833e5295a8bc (diff)
downloadNim-c694d8e4fd6a14ab6a79fe6359033a4be6133b8c.tar.gz
custom pragmas: correct error condition, remove outdated symkind whitelist (#21653)
* test not restricting custom pragma applied symbols

fixes #21652

* fix other test

* different patch

* fix tests

* actually test #18212 and other routines
-rw-r--r--compiler/pragmas.nim28
-rw-r--r--tests/pragmas/t8741.nim2
-rw-r--r--tests/pragmas/tcustom_pragma.nim29
-rw-r--r--tests/pragmas/tinvalidcustompragma.nim23
-rw-r--r--tests/stdlib/tsince.nim7
5 files changed, 73 insertions, 16 deletions
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index e51eb054b..2efef6fee 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -116,7 +116,15 @@ const
 proc invalidPragma*(c: PContext; n: PNode) =
   localError(c.config, n.info, "invalid pragma: " & renderTree(n, {renderNoComments}))
 proc illegalCustomPragma*(c: PContext, n: PNode, s: PSym) =
-  localError(c.config, n.info, "cannot attach a custom pragma to '" & s.name.s & "'")
+  var msg = "cannot attach a custom pragma to '" & s.name.s & "'"
+  if s != nil:
+    msg.add("; custom pragmas are not supported for ")
+    case s.kind
+    of skForVar: msg.add("`for` loop variables")
+    of skEnumField: msg.add("enum fields")
+    of skModule: msg.add("modules")
+    else: msg.add("symbol kind " & $s.kind)
+  localError(c.config, n.info, msg)
 
 proc pragmaProposition(c: PContext, n: PNode) =
   if n.kind notin nkPragmaCallKinds or n.len != 2:
@@ -755,7 +763,7 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
   else:
     result = qualifiedLookUp(c, n, {checkUndeclared})
 
-proc semCustomPragma(c: PContext, n: PNode): PNode =
+proc semCustomPragma(c: PContext, n: PNode, sym: PSym): PNode =
   var callNode: PNode
 
   if n.kind in {nkIdent, nkSym}:
@@ -774,6 +782,11 @@ proc semCustomPragma(c: PContext, n: PNode): PNode =
   if r.isNil or sfCustomPragma notin r[0].sym.flags:
     invalidPragma(c, n)
     return n
+  
+  # we have a valid custom pragma
+  if sym != nil and sym.kind in {skEnumField, skForVar, skModule}:
+    illegalCustomPragma(c, n, sym)
+    return n
 
   result = r
   # Transform the nkCall node back to its original form if possible
@@ -822,7 +835,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
     else: discard
     return
   elif key.kind notin nkIdentKinds:
-    n[i] = semCustomPragma(c, it)
+    n[i] = semCustomPragma(c, it, sym)
     return
   let ident = considerQuotedIdent(c, key)
   var userPragma = strTableGet(c.userPragmas, ident)
@@ -1248,13 +1261,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
     elif comesFromPush and whichKeyword(ident) != wInvalid:
       discard "ignore the .push pragma; it doesn't apply"
     else:
-      if sym == nil or (sym.kind in {skVar, skLet, skConst, skParam, skIterator,
-                        skField, skProc, skFunc, skConverter, skMethod, skType}):
-        n[i] = semCustomPragma(c, it)
-      elif sym != nil:
-        illegalCustomPragma(c, it, sym)
-      else:
-        invalidPragma(c, it)
+      # semCustomPragma gives appropriate error for invalid pragmas
+      n[i] = semCustomPragma(c, it, sym)
 
 proc overwriteLineInfo(n: PNode; info: TLineInfo) =
   n.info = info
diff --git a/tests/pragmas/t8741.nim b/tests/pragmas/t8741.nim
index 221c732b0..bf97b0e29 100644
--- a/tests/pragmas/t8741.nim
+++ b/tests/pragmas/t8741.nim
@@ -1,7 +1,7 @@
 discard """
   cmd: "nim check --hint:processing:off $file"
   errormsg: "3 is not two"
-  nimout: '''t8741.nim(13, 9) Error: cannot attach a custom pragma to 'a'
+  nimout: '''t8741.nim(13, 9) Error: invalid pragma: foobar
 t8741.nim(29, 15) template/generic instantiation of `onlyTwo` from here
 t8741.nim(25, 12) Error: 3 is not two
 '''
diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim
index ad25cad98..9ffa9a33d 100644
--- a/tests/pragmas/tcustom_pragma.nim
+++ b/tests/pragmas/tcustom_pragma.nim
@@ -399,12 +399,39 @@ block:
 
   discard Hello(a: 1.0, b: 12)
 
-# custom pragma on iterators
+# test routines
+block:
+  template prag {.pragma.}
+  proc hello {.prag.} = discard
+  iterator hello2: int {.prag.} = discard
+  template hello3(x: int): int {.prag.} = x
+  macro hello4(x: int): int {.prag.} = x
+  func hello5(x: int): int {.prag.} = x
+  doAssert hello.hasCustomPragma(prag)
+  doAssert hello2.hasCustomPragma(prag)
+  doAssert hello3.hasCustomPragma(prag)
+  doAssert hello4.hasCustomPragma(prag)
+  doAssert hello5.hasCustomPragma(prag)
+
+# test push doesn't break
 block:
   template prag {.pragma.}
   {.push prag.}
   proc hello = discard
   iterator hello2: int = discard
+  template hello3(x: int): int = x
+  macro hello4(x: int): int = x
+  func hello5(x: int): int = x
+  type
+    Foo = enum a
+    Bar[T] = ref object of RootObj
+      x: T
+      case y: bool
+      of false: discard
+      else:
+        when true: discard
+  for a in [1]: discard a
+  {.pop.}
 
 # issue #11511
 when false:
diff --git a/tests/pragmas/tinvalidcustompragma.nim b/tests/pragmas/tinvalidcustompragma.nim
new file mode 100644
index 000000000..a31695809
--- /dev/null
+++ b/tests/pragmas/tinvalidcustompragma.nim
@@ -0,0 +1,23 @@
+discard """
+  cmd: "nim check $file"
+"""
+
+# issue #21652
+type Foo = object
+template foo() {.tags:[Foo].} = #[tt.Error
+                     ^ invalid pragma: tags: [Foo]]#
+  discard
+
+{.foobar.} #[tt.Error
+  ^ invalid pragma: foobar]#
+type A = enum a {.foobar.} #[tt.Error
+                  ^ invalid pragma: foobar]#
+for b {.foobar.} in [1]: discard #[tt.Error
+        ^ invalid pragma: foobar]#
+template foobar {.pragma.}
+{.foobar.} #[tt.Error
+  ^ cannot attach a custom pragma to 'tinvalidcustompragma'; custom pragmas are not supported for modules]#
+type A = enum a {.foobar.} #[tt.Error
+                  ^ cannot attach a custom pragma to 'a'; custom pragmas are not supported for enum fields]#
+for b {.foobar.} in [1]: discard #[tt.Error
+        ^ cannot attach a custom pragma to 'b'; custom pragmas are not supported for `for` loop variables]#
diff --git a/tests/stdlib/tsince.nim b/tests/stdlib/tsince.nim
index 877a2bcda..a0a4229cb 100644
--- a/tests/stdlib/tsince.nim
+++ b/tests/stdlib/tsince.nim
@@ -27,7 +27,6 @@ doAssert ok
 since (99, 3):
   doAssert false
 
-when false:
-  # pending bug #15920
-  # Error: cannot attach a custom pragma to 'fun3'
-  template fun3(): int {.since: (1, 3).} = 12
+template fun3(): int {.since: (1, 3).} = 12
+
+doAssert declared(fun3)