diff options
author | Araq <rumpf_a@web.de> | 2015-08-02 00:35:02 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2015-08-02 02:55:59 +0200 |
commit | bd786812e7fd1cbd1b7a8f038000ac06ad08505e (patch) | |
tree | d8b27176a52c8c3bc969f4307c9fe92d9f51f7c1 /compiler/pragmas.nim | |
parent | 9275d5c6178e7674882dbbaa257f6bb2b5a7b6bf (diff) | |
download | Nim-bd786812e7fd1cbd1b7a8f038000ac06ad08505e.tar.gz |
fixes #3171
Diffstat (limited to 'compiler/pragmas.nim')
-rw-r--r-- | compiler/pragmas.nim | 544 |
1 files changed, 273 insertions, 271 deletions
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index c771155af..128a90138 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -591,280 +591,282 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, validPragmas: TSpecialWords): bool = var it = n.sons[i] var key = if it.kind == nkExprColonExpr: it.sons[0] else: it - if key.kind == nkIdent: - var userPragma = strTableGet(c.userPragmas, key.ident) - if userPragma != nil: - inc c.instCounter - if c.instCounter > 100: - globalError(it.info, errRecursiveDependencyX, userPragma.name.s) - pragma(c, sym, userPragma.ast, validPragmas) - # ensure the pragma is also remember for generic instantiations in other - # modules: - n.sons[i] = userPragma.ast - dec c.instCounter - else: - var k = whichKeyword(key.ident) - if k in validPragmas: - case k - of wExportc: - makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info) - incl(sym.flags, sfUsed) # avoid wrong hints - of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1")) - of wImportCompilerProc: - processImportCompilerProc(sym, getOptionalStr(c, it, "$1")) - of wExtern: setExternName(sym, expectStrLit(c, it)) - of wImmediate: - if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate) - else: invalidPragma(it) - of wDirty: - if sym.kind == skTemplate: incl(sym.flags, sfDirty) - else: invalidPragma(it) - of wImportCpp: - processImportCpp(sym, getOptionalStr(c, it, "$1")) - of wImportObjC: - processImportObjC(sym, getOptionalStr(c, it, "$1")) - of wAlign: - if sym.typ == nil: invalidPragma(it) - var align = expectIntLit(c, it) - if (not isPowerOfTwo(align) and align != 0) or align >% high(int16): - localError(it.info, errPowerOfTwoExpected) - else: - sym.typ.align = align.int16 - of wSize: - if sym.typ == nil: invalidPragma(it) - var size = expectIntLit(c, it) - if not isPowerOfTwo(size) or size <= 0 or size > 8: - localError(it.info, errPowerOfTwoExpected) - else: - sym.typ.size = size - of wNodecl: - noVal(it) - incl(sym.loc.flags, lfNoDecl) - of wPure, wAsmNoStackFrame: - noVal(it) - if sym != nil: - if k == wPure and sym.kind in routineKinds: invalidPragma(it) - else: incl(sym.flags, sfPure) - of wVolatile: - noVal(it) - incl(sym.flags, sfVolatile) - of wRegister: - noVal(it) - incl(sym.flags, sfRegister) - of wThreadVar: - noVal(it) - incl(sym.flags, sfThread) - of wDeadCodeElim: pragmaDeadCodeElim(c, it) - of wNoForward: pragmaNoForward(c, it) - of wMagic: processMagic(c, it, sym) - of wCompileTime: - noVal(it) - incl(sym.flags, sfCompileTime) - incl(sym.loc.flags, lfNoDecl) - of wGlobal: - noVal(it) - incl(sym.flags, sfGlobal) - incl(sym.flags, sfPure) - of wMerge: - # only supported for backwards compat, doesn't do anything anymore - noVal(it) - of wConstructor: - noVal(it) - incl(sym.flags, sfConstructor) - of wHeader: - var lib = getLib(c, libHeader, getStrLitNode(c, it)) - addToLib(lib, sym) - incl(sym.flags, sfImportc) - incl(sym.loc.flags, lfHeader) - incl(sym.loc.flags, lfNoDecl) - # implies nodecl, because otherwise header would not make sense - if sym.loc.r == nil: sym.loc.r = rope(sym.name.s) - of wDestructor: - sym.flags.incl sfOverriden - if sym.name.s.normalize != "destroy": - localError(n.info, errGenerated, "destructor has to be named 'destroy'") - of wOverride: - sym.flags.incl sfOverriden - of wNosideeffect: - noVal(it) - incl(sym.flags, sfNoSideEffect) - if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect) - of wSideeffect: - noVal(it) - incl(sym.flags, sfSideEffect) - of wNoreturn: - noVal(it) - incl(sym.flags, sfNoReturn) - of wDynlib: - processDynLib(c, it, sym) - of wCompilerproc: - noVal(it) # compilerproc may not get a string! - if sfFromGeneric notin sym.flags: markCompilerProc(sym) - of wProcVar: - noVal(it) - incl(sym.flags, sfProcvar) - of wDeprecated: - if it.kind == nkExprColonExpr: deprecatedStmt(c, it) - elif sym != nil: incl(sym.flags, sfDeprecated) - else: incl(c.module.flags, sfDeprecated) - of wVarargs: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfVarargs) - of wBorrow: - if sym.kind == skType: - typeBorrow(sym, it) - else: - noVal(it) - incl(sym.flags, sfBorrow) - of wFinal: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfFinal) - of wInheritable: - noVal(it) - if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it) - else: incl(sym.typ.flags, tfInheritable) - of wAcyclic: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfAcyclic) - of wShallow: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfShallow) - of wThread: - noVal(it) - incl(sym.flags, sfThread) - incl(sym.flags, sfProcvar) - if sym.typ != nil: incl(sym.typ.flags, tfThread) - of wGcSafe: - noVal(it) - if sym.kind != skType: incl(sym.flags, sfThread) - if sym.typ != nil: incl(sym.typ.flags, tfGcSafe) - else: invalidPragma(it) - of wPacked: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfPacked) - of wHint: message(it.info, hintUser, expectStrLit(c, it)) - of wWarning: message(it.info, warnUser, expectStrLit(c, it)) - of wError: - if sym != nil and sym.isRoutine: - # This is subtle but correct: the error *statement* is only - # allowed for top level statements. Seems to be easier than - # distinguishing properly between - # ``proc p() {.error}`` and ``proc p() = {.error: "msg".}`` - noVal(it) - incl(sym.flags, sfError) - else: - localError(it.info, errUser, expectStrLit(c, it)) - of wFatal: fatal(it.info, errUser, expectStrLit(c, it)) - of wDefine: processDefine(c, it) - of wUndef: processUndef(c, it) - of wCompile: processCompile(c, it) - of wLink: processCommonLink(c, it, linkNormal) - of wLinksys: processCommonLink(c, it, linkSys) - of wPassl: extccomp.addLinkOption(expectStrLit(c, it)) - of wPassc: extccomp.addCompileOption(expectStrLit(c, it)) - of wBreakpoint: pragmaBreakpoint(c, it) - of wWatchPoint: pragmaWatchpoint(c, it) - of wPush: - processPush(c, n, i + 1) - result = true - of wPop: processPop(c, it) - of wPragma: - processPragma(c, n, i) - result = true - of wDiscardable: - noVal(it) - if sym != nil: incl(sym.flags, sfDiscardable) - of wNoInit: - noVal(it) - if sym != nil: incl(sym.flags, sfNoInit) - of wCodegenDecl: processCodegenDecl(c, it, sym) - of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, - wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, - wLinedir, wStacktrace, wLinetrace, wOptimization, - wCallconv, - wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks, - wPatterns: - if processOption(c, it): - # calling conventions (boring...): - localError(it.info, errOptionExpected) - of FirstCallConv..LastCallConv: - assert(sym != nil) - if sym.typ == nil: invalidPragma(it) - else: sym.typ.callConv = wordToCallConv(k) - of wEmit: pragmaEmit(c, it) - of wUnroll: pragmaUnroll(c, it) - of wLinearScanEnd, wComputedGoto: noVal(it) - of wEffects: - # is later processed in effect analysis: - noVal(it) - of wIncompleteStruct: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfIncompleteStruct) - of wUnchecked: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfUncheckedArray) - of wUnion: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfUnion) - of wRequiresInit: - noVal(it) - if sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfNeedsInit) - of wByRef: - noVal(it) - if sym == nil or sym.typ == nil: - if processOption(c, it): localError(it.info, errOptionExpected) - else: - incl(sym.typ.flags, tfByRef) - of wByCopy: - noVal(it) - if sym.kind != skType or sym.typ == nil: invalidPragma(it) - else: incl(sym.typ.flags, tfByCopy) - of wInject, wGensym: - # We check for errors, but do nothing with these pragmas otherwise - # as they are handled directly in 'evalTemplate'. - noVal(it) - if sym == nil: invalidPragma(it) - of wLine: pragmaLine(c, it) - of wRaises, wTags: pragmaRaisesOrTags(c, it) - of wLocks: - if sym == nil: pragmaLockStmt(c, it) - elif sym.typ == nil: invalidPragma(it) - else: sym.typ.lockLevel = pragmaLocks(c, it) - of wGuard: - if sym == nil or sym.kind notin {skVar, skLet, skField}: - invalidPragma(it) - else: - sym.guard = pragmaGuard(c, it, sym.kind) - of wGoto: - if sym == nil or sym.kind notin {skVar, skLet}: - invalidPragma(it) - else: - sym.flags.incl sfGoto - of wInjectStmt: - if it.kind != nkExprColonExpr: - localError(it.info, errExprExpected) - else: - it.sons[1] = c.semExpr(c, it.sons[1]) - of wExperimental: - noVal(it) - if isTopLevel(c): - c.module.flags.incl sfExperimental - else: - localError(it.info, "'experimental' pragma only valid as toplevel statement") - of wNoRewrite: + if key.kind == nkBracketExpr: + processNote(c, it) + return + let ident = considerQuotedIdent(key) + var userPragma = strTableGet(c.userPragmas, ident) + if userPragma != nil: + inc c.instCounter + if c.instCounter > 100: + globalError(it.info, errRecursiveDependencyX, userPragma.name.s) + pragma(c, sym, userPragma.ast, validPragmas) + # ensure the pragma is also remember for generic instantiations in other + # modules: + n.sons[i] = userPragma.ast + dec c.instCounter + else: + var k = whichKeyword(ident) + if k in validPragmas: + case k + of wExportc: + makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info) + incl(sym.flags, sfUsed) # avoid wrong hints + of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1")) + of wImportCompilerProc: + processImportCompilerProc(sym, getOptionalStr(c, it, "$1")) + of wExtern: setExternName(sym, expectStrLit(c, it)) + of wImmediate: + if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate) + else: invalidPragma(it) + of wDirty: + if sym.kind == skTemplate: incl(sym.flags, sfDirty) + else: invalidPragma(it) + of wImportCpp: + processImportCpp(sym, getOptionalStr(c, it, "$1")) + of wImportObjC: + processImportObjC(sym, getOptionalStr(c, it, "$1")) + of wAlign: + if sym.typ == nil: invalidPragma(it) + var align = expectIntLit(c, it) + if (not isPowerOfTwo(align) and align != 0) or align >% high(int16): + localError(it.info, errPowerOfTwoExpected) + else: + sym.typ.align = align.int16 + of wSize: + if sym.typ == nil: invalidPragma(it) + var size = expectIntLit(c, it) + if not isPowerOfTwo(size) or size <= 0 or size > 8: + localError(it.info, errPowerOfTwoExpected) + else: + sym.typ.size = size + of wNodecl: + noVal(it) + incl(sym.loc.flags, lfNoDecl) + of wPure, wAsmNoStackFrame: + noVal(it) + if sym != nil: + if k == wPure and sym.kind in routineKinds: invalidPragma(it) + else: incl(sym.flags, sfPure) + of wVolatile: + noVal(it) + incl(sym.flags, sfVolatile) + of wRegister: + noVal(it) + incl(sym.flags, sfRegister) + of wThreadVar: + noVal(it) + incl(sym.flags, sfThread) + of wDeadCodeElim: pragmaDeadCodeElim(c, it) + of wNoForward: pragmaNoForward(c, it) + of wMagic: processMagic(c, it, sym) + of wCompileTime: + noVal(it) + incl(sym.flags, sfCompileTime) + incl(sym.loc.flags, lfNoDecl) + of wGlobal: + noVal(it) + incl(sym.flags, sfGlobal) + incl(sym.flags, sfPure) + of wMerge: + # only supported for backwards compat, doesn't do anything anymore + noVal(it) + of wConstructor: + noVal(it) + incl(sym.flags, sfConstructor) + of wHeader: + var lib = getLib(c, libHeader, getStrLitNode(c, it)) + addToLib(lib, sym) + incl(sym.flags, sfImportc) + incl(sym.loc.flags, lfHeader) + incl(sym.loc.flags, lfNoDecl) + # implies nodecl, because otherwise header would not make sense + if sym.loc.r == nil: sym.loc.r = rope(sym.name.s) + of wDestructor: + sym.flags.incl sfOverriden + if sym.name.s.normalize != "destroy": + localError(n.info, errGenerated, "destructor has to be named 'destroy'") + of wOverride: + sym.flags.incl sfOverriden + of wNosideeffect: + noVal(it) + incl(sym.flags, sfNoSideEffect) + if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect) + of wSideeffect: + noVal(it) + incl(sym.flags, sfSideEffect) + of wNoreturn: + noVal(it) + incl(sym.flags, sfNoReturn) + of wDynlib: + processDynLib(c, it, sym) + of wCompilerproc: + noVal(it) # compilerproc may not get a string! + if sfFromGeneric notin sym.flags: markCompilerProc(sym) + of wProcVar: + noVal(it) + incl(sym.flags, sfProcvar) + of wDeprecated: + if it.kind == nkExprColonExpr: deprecatedStmt(c, it) + elif sym != nil: incl(sym.flags, sfDeprecated) + else: incl(c.module.flags, sfDeprecated) + of wVarargs: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfVarargs) + of wBorrow: + if sym.kind == skType: + typeBorrow(sym, it) + else: noVal(it) + incl(sym.flags, sfBorrow) + of wFinal: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfFinal) + of wInheritable: + noVal(it) + if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it) + else: incl(sym.typ.flags, tfInheritable) + of wAcyclic: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfAcyclic) + of wShallow: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfShallow) + of wThread: + noVal(it) + incl(sym.flags, sfThread) + incl(sym.flags, sfProcvar) + if sym.typ != nil: incl(sym.typ.flags, tfThread) + of wGcSafe: + noVal(it) + if sym.kind != skType: incl(sym.flags, sfThread) + if sym.typ != nil: incl(sym.typ.flags, tfGcSafe) else: invalidPragma(it) + of wPacked: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfPacked) + of wHint: message(it.info, hintUser, expectStrLit(c, it)) + of wWarning: message(it.info, warnUser, expectStrLit(c, it)) + of wError: + if sym != nil and sym.isRoutine: + # This is subtle but correct: the error *statement* is only + # allowed for top level statements. Seems to be easier than + # distinguishing properly between + # ``proc p() {.error}`` and ``proc p() = {.error: "msg".}`` + noVal(it) + incl(sym.flags, sfError) + else: + localError(it.info, errUser, expectStrLit(c, it)) + of wFatal: fatal(it.info, errUser, expectStrLit(c, it)) + of wDefine: processDefine(c, it) + of wUndef: processUndef(c, it) + of wCompile: processCompile(c, it) + of wLink: processCommonLink(c, it, linkNormal) + of wLinksys: processCommonLink(c, it, linkSys) + of wPassl: extccomp.addLinkOption(expectStrLit(c, it)) + of wPassc: extccomp.addCompileOption(expectStrLit(c, it)) + of wBreakpoint: pragmaBreakpoint(c, it) + of wWatchPoint: pragmaWatchpoint(c, it) + of wPush: + processPush(c, n, i + 1) + result = true + of wPop: processPop(c, it) + of wPragma: + processPragma(c, n, i) + result = true + of wDiscardable: + noVal(it) + if sym != nil: incl(sym.flags, sfDiscardable) + of wNoInit: + noVal(it) + if sym != nil: incl(sym.flags, sfNoInit) + of wCodegenDecl: processCodegenDecl(c, it, sym) + of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, + wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, + wLinedir, wStacktrace, wLinetrace, wOptimization, + wCallconv, + wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks, + wPatterns: + if processOption(c, it): + # calling conventions (boring...): + localError(it.info, errOptionExpected) + of FirstCallConv..LastCallConv: + assert(sym != nil) + if sym.typ == nil: invalidPragma(it) + else: sym.typ.callConv = wordToCallConv(k) + of wEmit: pragmaEmit(c, it) + of wUnroll: pragmaUnroll(c, it) + of wLinearScanEnd, wComputedGoto: noVal(it) + of wEffects: + # is later processed in effect analysis: + noVal(it) + of wIncompleteStruct: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfIncompleteStruct) + of wUnchecked: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfUncheckedArray) + of wUnion: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfUnion) + of wRequiresInit: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfNeedsInit) + of wByRef: + noVal(it) + if sym == nil or sym.typ == nil: + if processOption(c, it): localError(it.info, errOptionExpected) + else: + incl(sym.typ.flags, tfByRef) + of wByCopy: + noVal(it) + if sym.kind != skType or sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfByCopy) + of wInject, wGensym: + # We check for errors, but do nothing with these pragmas otherwise + # as they are handled directly in 'evalTemplate'. + noVal(it) + if sym == nil: invalidPragma(it) + of wLine: pragmaLine(c, it) + of wRaises, wTags: pragmaRaisesOrTags(c, it) + of wLocks: + if sym == nil: pragmaLockStmt(c, it) + elif sym.typ == nil: invalidPragma(it) + else: sym.typ.lockLevel = pragmaLocks(c, it) + of wGuard: + if sym == nil or sym.kind notin {skVar, skLet, skField}: + invalidPragma(it) + else: + sym.guard = pragmaGuard(c, it, sym.kind) + of wGoto: + if sym == nil or sym.kind notin {skVar, skLet}: + invalidPragma(it) + else: + sym.flags.incl sfGoto + of wInjectStmt: + if it.kind != nkExprColonExpr: + localError(it.info, errExprExpected) + else: + it.sons[1] = c.semExpr(c, it.sons[1]) + of wExperimental: + noVal(it) + if isTopLevel(c): + c.module.flags.incl sfExperimental + else: + localError(it.info, "'experimental' pragma only valid as toplevel statement") + of wNoRewrite: + noVal(it) else: invalidPragma(it) - else: processNote(c, it) + else: invalidPragma(it) proc implicitPragmas*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) = |