gratuitous casting away const

Started by Mark Dilgerover 9 years ago6 messages
#1Mark Dilger
hornschnorter@gmail.com

Friends,

There are places in the code that cast away const for no apparent
reason, fixed like such:

diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 3143bd9..fe2cfc2 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -409,8 +409,8 @@ static int
 reorderqueue_cmp(const pairingheap_node *a, const pairingheap_node *b,
                                 void *arg)
 {
-       ReorderTuple *rta = (ReorderTuple *) a;
-       ReorderTuple *rtb = (ReorderTuple *) b;
+       const ReorderTuple *rta = (const ReorderTuple *) a;
+       const ReorderTuple *rtb = (const ReorderTuple *) b;
        IndexScanState *node = (IndexScanState *) arg;

return -cmp_orderbyvals(rta->orderbyvals, rta->orderbynulls,

There are also places which appear to cast away const due to using
typedefs that don't include const, which make for a more messy fix,
like such:

diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c
index 73aa0c0..9e157a3 100644
--- a/src/backend/storage/page/bufpage.c
+++ b/src/backend/storage/page/bufpage.c
@@ -1037,7 +1037,7 @@ PageIndexTupleDeleteNoCompact(Page page, OffsetNumber offnum)
  */
 bool
 PageIndexTupleOverwrite(Page page, OffsetNumber offnum,
-                                               Item newtup, Size newsize)
+                                               const char *newtup, Size newsize)
 {
        PageHeader      phdr = (PageHeader) page;
        ItemId          tupid;
diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h
index ad4ab5f..cd97a1a 100644
--- a/src/include/storage/bufpage.h
+++ b/src/include/storage/bufpage.h
@@ -431,7 +431,7 @@ extern void PageIndexTupleDelete(Page page, OffsetNumber offset);
 extern void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems);
 extern void PageIndexTupleDeleteNoCompact(Page page, OffsetNumber offset);
 extern bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum,
-                                               Item newtup, Size newsize);
+                                               const char *newtup, Size newsize);
 extern char *PageSetChecksumCopy(Page page, BlockNumber blkno);
 extern void PageSetChecksumInplace(Page page, BlockNumber blkno);

Are these castings away of const consistent with the project's coding standards?
Would patches to not cast away const be considered?

Thanks,

Mark Dilger

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Mark Dilger (#1)
Re: gratuitous casting away const

Mark Dilger <hornschnorter@gmail.com> writes:

Would patches to not cast away const be considered?

In general, yes, but I'm not especially in favor of something like this:

bool
PageIndexTupleOverwrite(Page page, OffsetNumber offnum,
-                                               Item newtup, Size newsize)
+                                               const char *newtup, Size newsize)
{

since that seems to be discarding type information in order to add
"const"; does not seem like a net benefit from here.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#3Mark Dilger
hornschnorter@gmail.com
In reply to: Tom Lane (#2)
Re: gratuitous casting away const

On Sep 20, 2016, at 1:06 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Mark Dilger <hornschnorter@gmail.com> writes:

Would patches to not cast away const be considered?

In general, yes, but I'm not especially in favor of something like this:

bool
PageIndexTupleOverwrite(Page page, OffsetNumber offnum,
-                                               Item newtup, Size newsize)
+                                               const char *newtup, Size newsize)
{

since that seems to be discarding type information in order to add
"const"; does not seem like a net benefit from here.

The following seems somewhere in between, with ItemPointer
changing to const ItemPointerData *. I expect you would not care
for this change, but thought I'd check to see where you draw the line:

diff --git a/src/backend/access/gin/ginbulk.c b/src/backend/access/gin/ginbulk.c
index 71c64e4..903b01f 100644
--- a/src/backend/access/gin/ginbulk.c
+++ b/src/backend/access/gin/ginbulk.c
@@ -244,7 +244,7 @@ ginInsertBAEntries(BuildAccumulator *accum,
 static int
 qsortCompareItemPointers(const void *a, const void *b)
 {
-   int         res = ginCompareItemPointers((ItemPointer) a, (ItemPointer) b);
+   int         res = ginCompareItemPointers((const ItemPointerData *) a, (const ItemPointerData *) b);
    /* Assert that there are no equal item pointers being sorted */
    Assert(res != 0);
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
index bf589ab..2e5a7dff 100644
--- a/src/include/access/gin_private.h
+++ b/src/include/access/gin_private.h
@@ -968,7 +968,7 @@ extern ItemPointer ginMergeItemPointers(ItemPointerData *a, uint32 na,
  * so we want this to be inlined.
  */
 static inline int
-ginCompareItemPointers(ItemPointer a, ItemPointer b)
+ginCompareItemPointers(const ItemPointerData *a, const ItemPointerData *b)
 {
    uint64      ia = (uint64) a->ip_blkid.bi_hi << 32 | (uint64) a->ip_blkid.bi_lo << 16 | a->ip_posid;
    uint64      ib = (uint64) b->ip_blkid.bi_hi << 32 | (uint64) b->ip_blkid.bi_lo << 16 | b->ip_posid;

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Mark Dilger (#3)
Re: gratuitous casting away const

Mark Dilger <hornschnorter@gmail.com> writes:

On Sep 20, 2016, at 1:06 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
... that seems to be discarding type information in order to add
"const"; does not seem like a net benefit from here.

The following seems somewhere in between, with ItemPointer
changing to const ItemPointerData *. I expect you would not care
for this change, but thought I'd check to see where you draw the line:

I'd call this kind of a wash, I guess. I'd be more excited about it if
the change allowed removal of an actual cast-away-of-constness somewhere.

I suppose it's a bit of a chicken and egg situation, in that the lack
of const markings on leaf subroutines discourages use of "const" in
callers, and you have to start somewhere if you want to make it better.
But I don't really want to just plaster "const" onto individual functions
without some larger vision of where we're going and which code is going
to benefit. Otherwise it seems like mostly just code churn.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#5Mark Dilger
hornschnorter@gmail.com
In reply to: Tom Lane (#4)
Re: gratuitous casting away const

On Sep 22, 2016, at 9:14 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

I'd call this kind of a wash, I guess. I'd be more excited about it if
the change allowed removal of an actual cast-away-of-constness somewhere.

I suppose it's a bit of a chicken and egg situation, in that the lack
of const markings on leaf subroutines discourages use of "const" in
callers, and you have to start somewhere if you want to make it better.
But I don't really want to just plaster "const" onto individual functions
without some larger vision of where we're going and which code is going
to benefit. Otherwise it seems like mostly just code churn.

regards, tom lane

I have two purposes in doing this. First, I find the code more self-documenting
this way. Second, I can get whole directories to compile cleanly without
warnings using the -Wcast-qual flag, where currently that flag results in
warnings. That makes it possible to add cast-qual to more individual source
directories' Makefiles than I can currently do while still using -Werror in
Makefile.global.

Now, I'm not proposing that everybody else needs to have -Wcast-qual. I'm
just saying that I'd like to be able to have that in my copy of the project.

mark

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6Mark Dilger
hornschnorter@gmail.com
In reply to: Mark Dilger (#5)
1 attachment(s)
Re: gratuitous casting away const

Friends,

here is another patch, this time fixing the casting away of const
in the regex code.

Mark Dilger

Attachments:

regex.patch.1application/octet-stream; name=regex.patch.1Download
diff --git a/src/backend/regex/regc_locale.c b/src/backend/regex/regc_locale.c
index 7cb3a40..3e2d3be 100644
--- a/src/backend/regex/regc_locale.c
+++ b/src/backend/regex/regc_locale.c
@@ -742,7 +742,7 @@ static int						/* 0 for equal, nonzero for unequal */
 cmp(const chr *x, const chr *y, /* strings to compare */
 	size_t len)					/* exact length of comparison */
 {
-	return memcmp(VS(x), VS(y), len * sizeof(chr));
+	return memcmp((const void *)x, (const void *)y, len * sizeof(chr));
 }
 
 /*
diff --git a/src/backend/regex/regcomp.c b/src/backend/regex/regcomp.c
index ed95474..90a134d 100644
--- a/src/backend/regex/regcomp.c
+++ b/src/backend/regex/regcomp.c
@@ -375,7 +375,7 @@ pg_regcomp(regex_t *re,
 	re->re_csize = sizeof(chr);
 	re->re_collation = collation;
 	re->re_guts = NULL;
-	re->re_fns = VS(&functions);
+	re->re_fns = &functions;
 
 	/* more complex setup, malloced things */
 	re->re_guts = VS(MALLOC(sizeof(struct guts)));
diff --git a/src/backend/regex/rege_dfa.c b/src/backend/regex/rege_dfa.c
index b98c9d3..46dd918 100644
--- a/src/backend/regex/rege_dfa.c
+++ b/src/backend/regex/rege_dfa.c
@@ -38,19 +38,19 @@
  * On success, returns match endpoint address.  Returns NULL on no match.
  * Internal errors also return NULL, with v->err set.
  */
-static chr *
+static const chr *
 longest(struct vars * v,
 		struct dfa * d,
-		chr *start,				/* where the match should start */
-		chr *stop,				/* match must end at or before here */
+		const chr *start,		/* where the match should start */
+		const chr *stop,		/* match must end at or before here */
 		int *hitstopp)			/* record whether hit v->stop, if non-NULL */
 {
-	chr		   *cp;
-	chr		   *realstop = (stop == v->stop) ? stop : stop + 1;
+	const chr  *cp;
+	const chr  *realstop = (stop == v->stop) ? stop : stop + 1;
 	color		co;
 	struct sset *css;
 	struct sset *ss;
-	chr		   *post;
+	const chr  *post;
 	int			i;
 	struct colormap *cm = d->cm;
 
@@ -164,18 +164,18 @@ longest(struct vars * v,
  * On success, returns match endpoint address.  Returns NULL on no match.
  * Internal errors also return NULL, with v->err set.
  */
-static chr *
+static const chr *
 shortest(struct vars * v,
 		 struct dfa * d,
-		 chr *start,			/* where the match should start */
-		 chr *min,				/* match must end at or after here */
-		 chr *max,				/* match must end at or before here */
-		 chr **coldp,			/* store coldstart pointer here, if non-NULL */
+		 const chr *start,		/* where the match should start */
+		 const chr *min,		/* match must end at or after here */
+		 const chr *max,		/* match must end at or before here */
+		 const chr **coldp,		/* store coldstart pointer here, if non-NULL */
 		 int *hitstopp)			/* record whether hit v->stop, if non-NULL */
 {
-	chr		   *cp;
-	chr		   *realmin = (min == v->stop) ? min : min + 1;
-	chr		   *realmax = (max == v->stop) ? max : max + 1;
+	const chr  *cp;
+	const chr  *realmin = (min == v->stop) ? min : min + 1;
+	const chr  *realmax = (max == v->stop) ? max : max + 1;
 	color		co;
 	struct sset *css;
 	struct sset *ss;
@@ -302,11 +302,11 @@ shortest(struct vars * v,
 static int
 matchuntil(struct vars * v,
 		   struct dfa * d,
-		   chr *probe,			/* we want to know if a match ends here */
-		   struct sset ** lastcss,		/* state storage across calls */
-		   chr **lastcp)		/* state storage across calls */
+		   const chr *probe,		/* we want to know if a match ends here */
+		   struct sset ** lastcss,	/* state storage across calls */
+		   const chr **lastcp)		/* state storage across calls */
 {
-	chr		   *cp = *lastcp;
+	const chr  *cp = *lastcp;
 	color		co;
 	struct sset *css = *lastcss;
 	struct sset *ss;
@@ -413,12 +413,12 @@ matchuntil(struct vars * v,
 /*
  * lastcold - determine last point at which no progress had been made
  */
-static chr *					/* endpoint, or NULL */
+static const chr *					/* endpoint, or NULL */
 lastcold(struct vars * v,
 		 struct dfa * d)
 {
 	struct sset *ss;
-	chr		   *nopr;
+	const chr   *nopr;
 	int			i;
 
 	nopr = d->lastnopr;
@@ -556,7 +556,7 @@ hash(unsigned *uv,
 static struct sset *
 initialize(struct vars * v,
 		   struct dfa * d,
-		   chr *start)
+		   const chr *start)
 {
 	struct sset *ss;
 	int			i;
@@ -604,8 +604,8 @@ miss(struct vars * v,
 	 struct dfa * d,
 	 struct sset * css,
 	 color co,
-	 chr *cp,					/* next chr */
-	 chr *start)				/* where the attempt got started */
+	 const chr *cp,					/* next chr */
+	 const chr *start)				/* where the attempt got started */
 {
 	struct cnfa *cnfa = d->cnfa;
 	int			i;
@@ -742,13 +742,13 @@ miss(struct vars * v,
 static int						/* predicate:  constraint satisfied? */
 lacon(struct vars * v,
 	  struct cnfa * pcnfa,		/* parent cnfa */
-	  chr *cp,
+	  const chr *cp,
 	  color co)					/* "color" of the lookaround constraint */
 {
 	int			n;
 	struct subre *sub;
 	struct dfa *d;
-	chr		   *end;
+	const chr  *end;
 	int			satisfied;
 
 	/* Since this is recursive, it could be driven to stack overflow */
@@ -769,7 +769,7 @@ lacon(struct vars * v,
 	{
 		/* used to use longest() here, but shortest() could be much cheaper */
 		end = shortest(v, d, cp, cp, v->stop,
-					   (chr **) NULL, (int *) NULL);
+					   (const chr **) NULL, (int *) NULL);
 		satisfied = LATYPE_IS_POS(sub->subno) ? (end != NULL) : (end == NULL);
 	}
 	else
@@ -799,8 +799,8 @@ lacon(struct vars * v,
 static struct sset *
 getvacant(struct vars * v,
 		  struct dfa * d,
-		  chr *cp,
-		  chr *start)
+		  const chr *cp,
+		  const chr *start)
 {
 	int			i;
 	struct sset *ss;
@@ -870,13 +870,13 @@ getvacant(struct vars * v,
 static struct sset *
 pickss(struct vars * v,
 	   struct dfa * d,
-	   chr *cp,
-	   chr *start)
+	   const chr *cp,
+	   const chr *start)
 {
 	int			i;
 	struct sset *ss;
 	struct sset *end;
-	chr		   *ancient;
+	const chr   *ancient;
 
 	/* shortcut for cases where cache isn't full */
 	if (d->nssused < d->nssets)
diff --git a/src/backend/regex/regexec.c b/src/backend/regex/regexec.c
index 5cbfd9b..700be35 100644
--- a/src/backend/regex/regexec.c
+++ b/src/backend/regex/regexec.c
@@ -55,7 +55,7 @@ struct sset
 #define  LOCKED		 04			/* locked in cache */
 #define  NOPROGRESS  010		/* zero-progress state set */
 	struct arcp ins;			/* chain of inarcs pointing here */
-	chr		   *lastseen;		/* last entered on arrival here */
+	const chr   *lastseen;		/* last entered on arrival here */
 	struct sset **outs;			/* outarc vector indexed by color */
 	struct arcp *inchain;		/* chain-pointer vector for outarcs */
 };
@@ -74,8 +74,8 @@ struct dfa
 	struct arcp *incarea;		/* inchain storage */
 	struct cnfa *cnfa;
 	struct colormap *cm;
-	chr		   *lastpost;		/* location of last cache-flushed success */
-	chr		   *lastnopr;		/* location of last cache-flushed NOPROGRESS */
+	const chr   *lastpost;		/* location of last cache-flushed success */
+	const chr   *lastnopr;		/* location of last cache-flushed NOPROGRESS */
 	struct sset *search;		/* replacement-search-pointer memory */
 	int			cptsmalloced;	/* were the areas individually malloced? */
 	char	   *mallocarea;		/* self, or master malloced area, or NULL */
@@ -108,14 +108,14 @@ struct vars
 	size_t		nmatch;
 	regmatch_t *pmatch;
 	rm_detail_t *details;
-	chr		   *start;			/* start of string */
-	chr		   *search_start;	/* search start of string */
-	chr		   *stop;			/* just past end of string */
+	const chr   *start;			/* start of string */
+	const chr   *search_start;	/* search start of string */
+	const chr   *stop;			/* just past end of string */
 	int			err;			/* error code if any (0 none) */
 	struct dfa **subdfas;		/* per-tree-subre DFAs */
 	struct dfa **ladfas;		/* per-lacon-subre DFAs */
 	struct sset **lblastcss;	/* per-lacon-subre lookbehind restart data */
-	chr		  **lblastcp;		/* per-lacon-subre lookbehind restart data */
+	const chr  **lblastcp;		/* per-lacon-subre lookbehind restart data */
 	struct smalldfa dfa1;
 	struct smalldfa dfa2;
 };
@@ -138,31 +138,31 @@ static struct dfa *getsubdfa(struct vars *, struct subre *);
 static struct dfa *getladfa(struct vars *, int);
 static int	find(struct vars *, struct cnfa *, struct colormap *);
 static int	cfind(struct vars *, struct cnfa *, struct colormap *);
-static int	cfindloop(struct vars *, struct cnfa *, struct colormap *, struct dfa *, struct dfa *, chr **);
+static int	cfindloop(struct vars *, struct cnfa *, struct colormap *, struct dfa *, struct dfa *, const chr **);
 static void zapallsubs(regmatch_t *, size_t);
 static void zaptreesubs(struct vars *, struct subre *);
-static void subset(struct vars *, struct subre *, chr *, chr *);
-static int	cdissect(struct vars *, struct subre *, chr *, chr *);
-static int	ccondissect(struct vars *, struct subre *, chr *, chr *);
-static int	crevcondissect(struct vars *, struct subre *, chr *, chr *);
-static int	cbrdissect(struct vars *, struct subre *, chr *, chr *);
-static int	caltdissect(struct vars *, struct subre *, chr *, chr *);
-static int	citerdissect(struct vars *, struct subre *, chr *, chr *);
-static int	creviterdissect(struct vars *, struct subre *, chr *, chr *);
+static void subset(struct vars *, struct subre *, const chr *, const chr *);
+static int	cdissect(struct vars *, struct subre *, const chr *, const chr *);
+static int	ccondissect(struct vars *, struct subre *, const chr *, const chr *);
+static int	crevcondissect(struct vars *, struct subre *, const chr *, const chr *);
+static int	cbrdissect(struct vars *, struct subre *, const chr *, const chr *);
+static int	caltdissect(struct vars *, struct subre *, const chr *, const chr *);
+static int	citerdissect(struct vars *, struct subre *, const chr *, const chr *);
+static int	creviterdissect(struct vars *, struct subre *, const chr *, const chr *);
 
 /* === rege_dfa.c === */
-static chr *longest(struct vars *, struct dfa *, chr *, chr *, int *);
-static chr *shortest(struct vars *, struct dfa *, chr *, chr *, chr *, chr **, int *);
-static int	matchuntil(struct vars *, struct dfa *, chr *, struct sset **, chr **);
-static chr *lastcold(struct vars *, struct dfa *);
+static const chr *longest(struct vars *, struct dfa *, const chr *, const chr *, int *);
+static const chr *shortest(struct vars *, struct dfa *, const chr *, const chr *, const chr *, const chr **, int *);
+static int	matchuntil(struct vars *, struct dfa *, const chr *, struct sset **, const chr **);
+static const chr *lastcold(struct vars *, struct dfa *);
 static struct dfa *newdfa(struct vars *, struct cnfa *, struct colormap *, struct smalldfa *);
 static void freedfa(struct dfa *);
 static unsigned hash(unsigned *, int);
-static struct sset *initialize(struct vars *, struct dfa *, chr *);
-static struct sset *miss(struct vars *, struct dfa *, struct sset *, color, chr *, chr *);
-static int	lacon(struct vars *, struct cnfa *, chr *, color);
-static struct sset *getvacant(struct vars *, struct dfa *, chr *, chr *);
-static struct sset *pickss(struct vars *, struct dfa *, chr *, chr *);
+static struct sset *initialize(struct vars *, struct dfa *, const chr *);
+static struct sset *miss(struct vars *, struct dfa *, struct sset *, color, const chr *, const chr *);
+static int	lacon(struct vars *, struct cnfa *, const chr *, color);
+static struct sset *getvacant(struct vars *, struct dfa *, const chr *, const chr *);
+static struct sset *pickss(struct vars *, struct dfa *, const chr *, const chr *);
 
 
 /*
@@ -227,9 +227,9 @@ pg_regexec(regex_t *re,
 	else
 		v->pmatch = pmatch;
 	v->details = details;
-	v->start = (chr *) string;
-	v->search_start = (chr *) string + search_start;
-	v->stop = (chr *) string + len;
+	v->start = (const chr *) string;
+	v->search_start = (const chr *) string + search_start;
+	v->stop = (const chr *) string + len;
 	v->err = 0;
 	v->subdfas = NULL;
 	v->ladfas = NULL;
@@ -266,7 +266,7 @@ pg_regexec(regex_t *re,
 		for (i = 0; i < n; i++)
 			v->ladfas[i] = NULL;
 		v->lblastcss = (struct sset **) MALLOC(n * sizeof(struct sset *));
-		v->lblastcp = (chr **) MALLOC(n * sizeof(chr *));
+		v->lblastcp = (const chr **) MALLOC(n * sizeof(const chr *));
 		if (v->lblastcss == NULL || v->lblastcp == NULL)
 		{
 			st = REG_ESPACE;
@@ -378,11 +378,11 @@ find(struct vars * v,
 {
 	struct dfa *s;
 	struct dfa *d;
-	chr		   *begin;
-	chr		   *end = NULL;
-	chr		   *cold;
-	chr		   *open;			/* open and close of range of possible starts */
-	chr		   *close;
+	const chr  *begin;
+	const chr  *end = NULL;
+	const chr  *cold;
+	const chr  *open;			/* open and close of range of possible starts */
+	const chr  *close;
 	int			hitend;
 	int			shorter = (v->g->tree->flags & SHORTER) ? 1 : 0;
 
@@ -423,7 +423,7 @@ find(struct vars * v,
 		MDEBUG(("\nfind trying at %ld\n", LOFF(begin)));
 		if (shorter)
 			end = shortest(v, d, begin, begin, v->stop,
-						   (chr **) NULL, &hitend);
+						   (const chr **) NULL, &hitend);
 		else
 			end = longest(v, d, begin, v->stop, &hitend);
 		if (ISERR())
@@ -469,7 +469,7 @@ cfind(struct vars * v,
 {
 	struct dfa *s;
 	struct dfa *d;
-	chr		   *cold;
+	const chr  *cold;
 	int			ret;
 
 	s = newdfa(v, &v->g->search, cm, &v->dfa1);
@@ -508,15 +508,15 @@ cfindloop(struct vars * v,
 		  struct colormap * cm,
 		  struct dfa * d,
 		  struct dfa * s,
-		  chr **coldp)			/* where to put coldstart pointer */
+		  const chr **coldp)	/* where to put coldstart pointer */
 {
-	chr		   *begin;
-	chr		   *end;
-	chr		   *cold;
-	chr		   *open;			/* open and close of range of possible starts */
-	chr		   *close;
-	chr		   *estart;
-	chr		   *estop;
+	const chr  *begin;
+	const chr  *end;
+	const chr  *cold;
+	const chr  *open;			/* open and close of range of possible starts */
+	const chr  *close;
+	const chr  *estart;
+	const chr  *estop;
 	int			er;
 	int			shorter = v->g->tree->flags & SHORTER;
 	int			hitend;
@@ -551,7 +551,7 @@ cfindloop(struct vars * v,
 				/* Here we use the top node's detailed RE */
 				if (shorter)
 					end = shortest(v, d, begin, estart,
-								   estop, (chr **) NULL, &hitend);
+								   estop, (const chr **) NULL, &hitend);
 				else
 					end = longest(v, d, begin, estop,
 								  &hitend);
@@ -659,8 +659,8 @@ zaptreesubs(struct vars * v,
 static void
 subset(struct vars * v,
 	   struct subre * sub,
-	   chr *begin,
-	   chr *end)
+	   const chr *begin,
+	   const chr *end)
 {
 	int			n = sub->subno;
 
@@ -691,8 +691,8 @@ subset(struct vars * v,
 static int						/* regexec return code */
 cdissect(struct vars * v,
 		 struct subre * t,
-		 chr *begin,			/* beginning of relevant substring */
-		 chr *end)				/* end of same */
+		 const chr *begin,		/* beginning of relevant substring */
+		 const chr *end)		/* end of same */
 {
 	int			er;
 
@@ -762,12 +762,12 @@ cdissect(struct vars * v,
 static int						/* regexec return code */
 ccondissect(struct vars * v,
 			struct subre * t,
-			chr *begin,			/* beginning of relevant substring */
-			chr *end)			/* end of same */
+			const chr *begin,	/* beginning of relevant substring */
+			const chr *end)		/* end of same */
 {
 	struct dfa *d;
 	struct dfa *d2;
-	chr		   *mid;
+	const chr  *mid;
 	int			er;
 
 	assert(t->op == '.');
@@ -840,12 +840,12 @@ ccondissect(struct vars * v,
 static int						/* regexec return code */
 crevcondissect(struct vars * v,
 			   struct subre * t,
-			   chr *begin,		/* beginning of relevant substring */
-			   chr *end)		/* end of same */
+			   const chr *begin,	/* beginning of relevant substring */
+			   const chr *end)		/* end of same */
 {
 	struct dfa *d;
 	struct dfa *d2;
-	chr		   *mid;
+	const chr  *mid;
 	int			er;
 
 	assert(t->op == '.');
@@ -860,7 +860,7 @@ crevcondissect(struct vars * v,
 	MDEBUG(("crevcon %d\n", t->id));
 
 	/* pick a tentative midpoint */
-	mid = shortest(v, d, begin, begin, end, (chr **) NULL, (int *) NULL);
+	mid = shortest(v, d, begin, begin, end, (const chr **) NULL, (int *) NULL);
 	NOERR();
 	if (mid == NULL)
 		return REG_NOMATCH;
@@ -895,7 +895,7 @@ crevcondissect(struct vars * v,
 			MDEBUG(("%d no midpoint\n", t->id));
 			return REG_NOMATCH;
 		}
-		mid = shortest(v, d, begin, mid + 1, end, (chr **) NULL, (int *) NULL);
+		mid = shortest(v, d, begin, mid + 1, end, (const chr **) NULL, (int *) NULL);
 		NOERR();
 		if (mid == NULL)
 		{
@@ -918,15 +918,15 @@ crevcondissect(struct vars * v,
 static int						/* regexec return code */
 cbrdissect(struct vars * v,
 		   struct subre * t,
-		   chr *begin,			/* beginning of relevant substring */
-		   chr *end)			/* end of same */
+		   const chr *begin,	/* beginning of relevant substring */
+		   const chr *end)		/* end of same */
 {
 	int			n = t->subno;
 	size_t		numreps;
 	size_t		tlen;
 	size_t		brlen;
-	chr		   *brstring;
-	chr		   *p;
+	const chr  *brstring;
+	const chr  *p;
 	int			min = t->min;
 	int			max = t->max;
 
@@ -999,8 +999,8 @@ cbrdissect(struct vars * v,
 static int						/* regexec return code */
 caltdissect(struct vars * v,
 			struct subre * t,
-			chr *begin,			/* beginning of relevant substring */
-			chr *end)			/* end of same */
+			const chr *begin,	/* beginning of relevant substring */
+			const chr *end)		/* end of same */
 {
 	struct dfa *d;
 	int			er;
@@ -1036,12 +1036,12 @@ caltdissect(struct vars * v,
 static int						/* regexec return code */
 citerdissect(struct vars * v,
 			 struct subre * t,
-			 chr *begin,		/* beginning of relevant substring */
-			 chr *end)			/* end of same */
+			 const chr *begin,	/* beginning of relevant substring */
+			 const chr *end)	/* end of same */
 {
 	struct dfa *d;
-	chr		  **endpts;
-	chr		   *limit;
+	const chr  **endpts;
+	const chr  *limit;
 	int			min_matches;
 	size_t		max_matches;
 	int			nverified;
@@ -1081,7 +1081,7 @@ citerdissect(struct vars * v,
 		max_matches = t->max;
 	if (max_matches < min_matches)
 		max_matches = min_matches;
-	endpts = (chr **) MALLOC((max_matches + 1) * sizeof(chr *));
+	endpts = (const chr **) MALLOC((max_matches + 1) * sizeof(const chr *));
 	if (endpts == NULL)
 		return REG_ESPACE;
 	endpts[0] = begin;
@@ -1197,7 +1197,7 @@ backtrack:
 		 */
 		while (k > 0)
 		{
-			chr		   *prev_end = endpts[k - 1];
+			const chr	   *prev_end = endpts[k - 1];
 
 			if (endpts[k] > prev_end)
 			{
@@ -1237,12 +1237,12 @@ backtrack:
 static int						/* regexec return code */
 creviterdissect(struct vars * v,
 				struct subre * t,
-				chr *begin,		/* beginning of relevant substring */
-				chr *end)		/* end of same */
+				const chr *begin,	/* beginning of relevant substring */
+				const chr *end)		/* end of same */
 {
 	struct dfa *d;
-	chr		  **endpts;
-	chr		   *limit;
+	const chr  **endpts;
+	const chr  *limit;
 	int			min_matches;
 	size_t		max_matches;
 	int			nverified;
@@ -1282,7 +1282,7 @@ creviterdissect(struct vars * v,
 		max_matches = t->max;
 	if (max_matches < min_matches)
 		max_matches = min_matches;
-	endpts = (chr **) MALLOC((max_matches + 1) * sizeof(chr *));
+	endpts = (const chr **) MALLOC((max_matches + 1) * sizeof(const chr *));
 	if (endpts == NULL)
 		return REG_ESPACE;
 	endpts[0] = begin;
@@ -1325,7 +1325,7 @@ creviterdissect(struct vars * v,
 
 		/* try to find an endpoint for the k'th sub-match */
 		endpts[k] = shortest(v, d, endpts[k - 1], limit, end,
-							 (chr **) NULL, (int *) NULL);
+							 (const chr **) NULL, (int *) NULL);
 		if (ISERR())
 		{
 			FREE(endpts);
diff --git a/src/backend/regex/regfree.c b/src/backend/regex/regfree.c
index ae17ae7..2aac3db 100644
--- a/src/backend/regex/regfree.c
+++ b/src/backend/regex/regfree.c
@@ -50,5 +50,5 @@ pg_regfree(regex_t *re)
 {
 	if (re == NULL)
 		return;
-	(*((struct fns *) re->re_fns)->free) (re);
+	(*((const struct fns *) re->re_fns)->free) (re);
 }
diff --git a/src/include/regex/regcustom.h b/src/include/regex/regcustom.h
index 04a1893..b97bce2 100644
--- a/src/include/regex/regcustom.h
+++ b/src/include/regex/regcustom.h
@@ -28,6 +28,18 @@
  * src/include/regex/regcustom.h
  */
 
+/*
+ * Modification Notice:
+ *
+ * I have modified the software in this regex package, including files in the
+ * src/include/regex and src/backend/regex directories, to avoid casting away
+ * const and enable compiling the software with the -Wcast-qual flag without
+ * warning.  This notice is given to comply with the license requirement, above,
+ * which requires me to indicate the origin and nature of modifications.
+ *
+ *		Mark Dilger, September 26, 2016
+ */
+
 /* headers if any */
 #include "postgres.h"
 
diff --git a/src/include/regex/regex.h b/src/include/regex/regex.h
index cc73db2..fed55ce 100644
--- a/src/include/regex/regex.h
+++ b/src/include/regex/regex.h
@@ -47,6 +47,8 @@
  */
 typedef long regoff_t;
 
+struct fns;
+
 /*
  * other interface types
  */
@@ -76,7 +78,7 @@ typedef struct
 	Oid			re_collation;	/* Collation that defines LC_CTYPE behavior */
 	/* the rest is opaque pointers to hidden innards */
 	char	   *re_guts;		/* `char *' is more portable than `void *' */
-	char	   *re_fns;
+	const struct fns   *re_fns;
 } regex_t;
 
 /* result reporting (may acquire more fields later) */
diff --git a/src/include/regex/regguts.h b/src/include/regex/regguts.h
index 69816f1..86eb6e0 100644
--- a/src/include/regex/regguts.h
+++ b/src/include/regex/regguts.h
@@ -450,10 +450,10 @@ struct fns
 };
 
 #define CANCEL_REQUESTED(re)  \
-	((*((struct fns *) (re)->re_fns)->cancel_requested) ())
+	((*((const struct fns *) (re)->re_fns)->cancel_requested) ())
 
 #define STACK_TOO_DEEP(re)	\
-	((*((struct fns *) (re)->re_fns)->stack_too_deep) ())
+	((*((const struct fns *) (re)->re_fns)->stack_too_deep) ())
 
 
 /*