On 16/10/2018 08:30, Andres Freund wrote:
> This just reminded me that a couple times I wanted a cast that casts
> away const, but otherwise makes sure the type stays the same. I don't
> think there's a way to do that in C, but we can write one that verifies
> the cast doesn't do something bad if gcc is used:
> 
> #if defined(HAVE__BUILTIN_TYPES_COMPATIBLE_P)
> #define unconstify(cst, var) 
> StaticAssertExpr(__builtin_types_compatible_p(__typeof(var), const cst), 
> "wrong cast"), (cst) (var)
> #else
> #define unconstify(cst, var) ((cst) (var))
> #endif
> 
> Does anybody besides me see value in adding a cleaned up version of
> that?

I've had the attached patch lying around.  As you can see there, there
are a few places where it could be useful, but not too many.

The name CONST_CAST() is adapted from C++.

Your version with __builtin_types_compatible_p() doesn't work for
casting between char * and const char *, so it wouldn't be very useful.

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From 31576b37687f44fc14bcf0990eb489466b74bf29 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pete...@gmx.net>
Date: Wed, 23 May 2018 09:10:51 -0400
Subject: [PATCH] Add CONST_CAST macro

---
 src/backend/utils/adt/json.c       | 4 ++--
 src/backend/utils/adt/misc.c       | 2 +-
 src/backend/utils/adt/varlena.c    | 4 ++--
 src/backend/utils/fmgr/dfmgr.c     | 4 ++--
 src/include/c.h                    | 6 ++++++
 src/interfaces/libpq/pqexpbuffer.c | 2 +-
 src/port/win32setlocale.c          | 2 +-
 7 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index 6f0fe94d63..6190b01dd2 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -207,12 +207,12 @@ IsValidJsonNumber(const char *str, int len)
         */
        if (*str == '-')
        {
-               dummy_lex.input = (char *) str + 1;
+               dummy_lex.input = CONST_CAST(char *, str) + 1;
                dummy_lex.input_length = len - 1;
        }
        else
        {
-               dummy_lex.input = (char *) str;
+               dummy_lex.input = CONST_CAST(char *, str);
                dummy_lex.input_length = len;
        }
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 6ea3679835..179ba81880 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -423,7 +423,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
                HeapTuple       tuple;
 
                /* cast-away-const is ugly but alternatives aren't much better 
*/
-               values[0] = (char *) ScanKeywords[funcctx->call_cntr].name;
+               values[0] = CONST_CAST(char *, 
ScanKeywords[funcctx->call_cntr].name);
 
                switch (ScanKeywords[funcctx->call_cntr].category)
                {
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index a5e812d026..a98ec2f8df 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -182,7 +182,7 @@ char *
 text_to_cstring(const text *t)
 {
        /* must cast away the const, unfortunately */
-       text       *tunpacked = pg_detoast_datum_packed((struct varlena *) t);
+       text       *tunpacked = pg_detoast_datum_packed(CONST_CAST(text *, t));
        int                     len = VARSIZE_ANY_EXHDR(tunpacked);
        char       *result;
 
@@ -213,7 +213,7 @@ void
 text_to_cstring_buffer(const text *src, char *dst, size_t dst_len)
 {
        /* must cast away the const, unfortunately */
-       text       *srcunpacked = pg_detoast_datum_packed((struct varlena *) 
src);
+       text       *srcunpacked = pg_detoast_datum_packed(CONST_CAST(text *, 
src));
        size_t          src_len = VARSIZE_ANY_EXHDR(srcunpacked);
 
        if (dst_len > 0)
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index 4a5cc7cfc7..b2ff7aef35 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -126,7 +126,7 @@ load_external_function(const char *filename, const char 
*funcname,
         * should declare its second argument as "const char *", but older
         * platforms might not, so for the time being we just cast away const.
         */
-       retval = (PGFunction) dlsym(lib_handle, (char *) funcname);
+       retval = (PGFunction) dlsym(lib_handle, CONST_CAST(char *, funcname));
 
        if (retval == NULL && signalNotFound)
                ereport(ERROR,
@@ -175,7 +175,7 @@ PGFunction
 lookup_external_function(void *filehandle, const char *funcname)
 {
        /* as above, cast away const for the time being */
-       return (PGFunction) dlsym(filehandle, (char *) funcname);
+       return (PGFunction) dlsym(filehandle, CONST_CAST(char *, funcname));
 }
 
 
diff --git a/src/include/c.h b/src/include/c.h
index 4a757bc8ea..6341b2512f 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -208,6 +208,12 @@
 #define unlikely(x) ((x) != 0)
 #endif
 
+/*
+ * Safer casting -- use this for casting away const or volatile.  It ensures
+ * that the source and target types are otherwise compatible.
+ */
+#define CONST_CAST(t, x) ((void)((t)0 == (x)), (t)(x))
+
 /*
  * CppAsString
  *             Convert the argument to a string, using the C preprocessor.
diff --git a/src/interfaces/libpq/pqexpbuffer.c 
b/src/interfaces/libpq/pqexpbuffer.c
index 43c36c3bff..4015b58a08 100644
--- a/src/interfaces/libpq/pqexpbuffer.c
+++ b/src/interfaces/libpq/pqexpbuffer.c
@@ -57,7 +57,7 @@ markPQExpBufferBroken(PQExpBuffer str)
         * to put oom_buffer in read-only storage, so that anyone who tries to
         * scribble on a broken PQExpBuffer will get a failure.
         */
-       str->data = (char *) oom_buffer;
+       str->data = CONST_CAST(char *, oom_buffer);
        str->len = 0;
        str->maxlen = 0;
 }
diff --git a/src/port/win32setlocale.c b/src/port/win32setlocale.c
index 0597c2afca..3514b5606a 100644
--- a/src/port/win32setlocale.c
+++ b/src/port/win32setlocale.c
@@ -183,7 +183,7 @@ pgwin32_setlocale(int category, const char *locale)
         * forbidden to modify, so casting away the "const" is innocuous.
         */
        if (result)
-               result = (char *) map_locale(locale_map_result, result);
+               result = CONST_CAST(char *, map_locale(locale_map_result, 
result));
 
        return result;
 }
-- 
2.19.1

Reply via email to