summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--generic/tclExecute.c46
-rw-r--r--generic/tclInt.h38
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 <msofer@users.sf.net>
+
+ * 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 <dgp@users.sourceforge.net>
* 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; \
}