From 412f81264a0156c5c2b473db6adcfba85dc81ed6 Mon Sep 17 00:00:00 2001 From: Miguel Sofer Date: Thu, 18 Sep 2008 15:43:10 +0000 Subject: * generic/tclExecute.c (NEXT_INST_F): * generic/tclInt.h (TCL_CT_ASSERT): new compile-time assertions, adapted from www.pixelbeat.org/programming/gcc/static_assert.html --- ChangeLog | 6 ++++++ generic/tclExecute.c | 46 ++++++++++++++++++++++++---------------------- generic/tclInt.h | 38 ++++++++++++++++++++------------------ 3 files changed, 50 insertions(+), 40 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0858384..6df17e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-09-18 Miguel Sofer + + * generic/tclExecute.c (NEXT_INST_F): + * generic/tclInt.h (TCL_CT_ASSERT): new compile-time assertions, + adapted from www.pixelbeat.org/programming/gcc/static_assert.html + 2008-09-17 Don Porter * generic/tclInt.h: Correct the TclGetLongFromObj, diff --git a/generic/tclExecute.c b/generic/tclExecute.c index ba7bd62..fd79931 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -14,7 +14,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclExecute.c,v 1.411 2008/09/10 13:24:12 msofer Exp $ + * RCS: @(#) $Id: tclExecute.c,v 1.412 2008/09/18 15:43:15 msofer Exp $ */ #include "tclInt.h" @@ -257,35 +257,37 @@ VarHashCreateVar( * resultHandling: 0 indicates no object should be pushed on the stack; * otherwise, push objResultPtr. If (result < 0), objResultPtr already * has the correct reference count. + * + * We use the new compile-time assertions to cheack that nCleanup is constant + * and within range. */ #define NEXT_INST_F(pcAdjustment, nCleanup, resultHandling) \ - if (nCleanup == 0) {\ - if (resultHandling != 0) {\ - if ((resultHandling) > 0) {\ - PUSH_OBJECT(objResultPtr);\ - } else {\ - *(++tosPtr) = objResultPtr;\ - }\ - } \ - pc += (pcAdjustment);\ - goto cleanup0;\ - } else if (resultHandling != 0) {\ - if ((resultHandling) > 0) {\ - Tcl_IncrRefCount(objResultPtr);\ - }\ - pc += (pcAdjustment);\ - switch (nCleanup) {\ - case 1: goto cleanup1_pushObjResultPtr;\ - case 2: goto cleanup2_pushObjResultPtr;\ - default: Tcl_Panic("bad usage of macro NEXT_INST_F");\ + TCL_CT_ASSERT((nCleanup >= 0) && (nCleanup <= 2)); \ + if (nCleanup == 0) { \ + if (resultHandling != 0) { \ + if ((resultHandling) > 0) { \ + PUSH_OBJECT(objResultPtr); \ + } else { \ + *(++tosPtr) = objResultPtr; \ + } \ + } \ + pc += (pcAdjustment); \ + goto cleanup0; \ + } else if (resultHandling != 0) { \ + if ((resultHandling) > 0) { \ + Tcl_IncrRefCount(objResultPtr); \ + } \ + pc += (pcAdjustment); \ + switch (nCleanup) { \ + case 1: goto cleanup1_pushObjResultPtr; \ + case 2: goto cleanup2_pushObjResultPtr; \ }\ } else {\ pc += (pcAdjustment);\ switch (nCleanup) {\ case 1: goto cleanup1;\ case 2: goto cleanup2;\ - default: Tcl_Panic("bad usage of macro NEXT_INST_F");\ }\ } @@ -2399,7 +2401,7 @@ TclExecuteByteCode( TclNewObj(newObjResultPtr); Tcl_IncrRefCount(newObjResultPtr); iPtr->objResultPtr = newObjResultPtr; - NEXT_INST_V(opnd, 0, -1); + NEXT_INST_F(opnd, 0, -1); } case INST_DUP: diff --git a/generic/tclInt.h b/generic/tclInt.h index 10deb4c..d13efb4 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -15,7 +15,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclInt.h,v 1.397 2008/09/17 18:11:32 dgp Exp $ + * RCS: @(#) $Id: tclInt.h,v 1.398 2008/09/18 15:43:21 msofer Exp $ */ #ifndef _TCLINT @@ -4035,13 +4035,27 @@ MODULE_SCOPE void TclBNInitBignumFromWideUInt(mp_int *bignum, ? 1 : 0))) /* + * Compile-time assertions: these produce a compile time error if + * the expression is not known to be true at compile time. + * If the assertion is known to be false, the compiler (or optimizer?) will + * error out with "division by zero". If the assertion cannot be evaluated at + * compile time, the compiler will error out with "non-static initializer". + * + * Adapted with permission from + * http://www.pixelbeat.org/programming/gcc/static_assert.html + */ + +#define TCL_ASSERT_CONCAT_(a, b) a##b +#define TCL_ASSERT_CONCAT(a, b) TCL_ASSERT_CONCAT_(a, b) +#define TCL_CT_ASSERT(e) \ + {enum { TCL_ASSERT_CONCAT(tclCtAssert_, __LINE__) = 1/(!!(e)) };} + +/* *---------------------------------------------------------------- * Allocator for small structs (<=sizeof(Tcl_Obj)) using the Tcl_Obj pool. * Only checked at compile time. * - * ONLY USE FOR CONSTANT nBytes: if you do and nBytes is too large, the - * compiler will error out with "duplicate case value" (thanks dkf!). If the - * size is dynamic, a panic will be compiled in for the wrong case. + * ONLY USE FOR CONSTANT nBytes. * * DO NOT LET THEM CROSS THREAD BOUNDARIES *---------------------------------------------------------------- @@ -4057,13 +4071,7 @@ MODULE_SCOPE void TclBNInitBignumFromWideUInt(mp_int *bignum, #define TclSmallAllocEx(interp, nbytes, memPtr) \ { \ Tcl_Obj *objPtr; \ - switch ((nbytes)>sizeof(Tcl_Obj)) { \ - case (2 +((nbytes)>sizeof(Tcl_Obj))): \ - case 3: \ - case 1: \ - Tcl_Panic("TclSmallAlloc: nBytes too large!"); \ - case 0: (void)0; \ - } \ + TCL_CT_ASSERT((nbytes)<=sizeof(Tcl_Obj)); \ TclIncrObjsAllocated(); \ TclAllocObjStorageEx((interp), (objPtr)); \ memPtr = (ClientData) (objPtr); \ @@ -4077,13 +4085,7 @@ MODULE_SCOPE void TclBNInitBignumFromWideUInt(mp_int *bignum, #define TclSmallAllocEx(interp, nbytes, memPtr) \ { \ Tcl_Obj *objPtr; \ - switch ((nbytes)>sizeof(Tcl_Obj)) { \ - case (2 +((nbytes)>sizeof(Tcl_Obj))): \ - case 3: \ - case 1: \ - Tcl_Panic("TclSmallAlloc: nBytes too large!"); \ - case 0: (void)0; \ - } \ + TCL_CT_ASSERT((nbytes)<=sizeof(Tcl_Obj)); \ TclNewObj(objPtr); \ memPtr = (ClientData) objPtr; \ } -- cgit v0.12