Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit b853eb9

Browse files
committed
Improve handling of ereport(ERROR) and elog(ERROR).
In commit 71450d7, we added code to inform suitably-intelligent compilers that ereport() doesn't return if the elevel is ERROR or higher. This patch extends that to elog(), and also fixes a double-evaluation hazard that the previous commit created in ereport(), as well as reducing the emitted code size. The elog() improvement requires the compiler to support __VA_ARGS__, which should be available in just about anything nowadays since it's required by C99. But our minimum language baseline is still C89, so add a configure test for that. The previous commit assumed that ereport's elevel could be evaluated twice, which isn't terribly safe --- there are already counterexamples in xlog.c. On compilers that have __builtin_constant_p, we can use that to protect the second test, since there's no possible optimization gain if the compiler doesn't know the value of elevel. Otherwise, use a local variable inside the macros to prevent double evaluation. The local-variable solution is inferior because (a) it leads to useless code being emitted when elevel isn't constant, and (b) it increases the optimization level needed for the compiler to recognize that subsequent code is unreachable. But it seems better than not teaching non-gcc compilers about unreachability at all. Lastly, if the compiler has __builtin_unreachable(), we can use that instead of abort(), resulting in a noticeable code savings since no function call is actually emitted. However, it seems wise to do this only in non-assert builds. In an assert build, continue to use abort(), so that the behavior will be predictable and debuggable if the "impossible" happens. These changes involve making the ereport and elog macros emit do-while statement blocks not just expressions, which forces small changes in a few call sites. Andres Freund, Tom Lane, Heikki Linnakangas
1 parent 4ae5ee6 commit b853eb9

File tree

12 files changed

+361
-15
lines changed

12 files changed

+361
-15
lines changed

config/c-compiler.m4

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ fi])# PGAC_C_FUNCNAME_SUPPORT
122122

123123

124124
# PGAC_C_STATIC_ASSERT
125-
# -----------------------
125+
# --------------------
126126
# Check if the C compiler understands _Static_assert(),
127127
# and define HAVE__STATIC_ASSERT if so.
128128
#
@@ -161,6 +161,63 @@ fi])# PGAC_C_TYPES_COMPATIBLE
161161

162162

163163

164+
# PGAC_C_BUILTIN_CONSTANT_P
165+
# -------------------------
166+
# Check if the C compiler understands __builtin_constant_p(),
167+
# and define HAVE__BUILTIN_CONSTANT_P if so.
168+
AC_DEFUN([PGAC_C_BUILTIN_CONSTANT_P],
169+
[AC_CACHE_CHECK(for __builtin_constant_p, pgac_cv__builtin_constant_p,
170+
[AC_TRY_COMPILE([static int x; static int y[__builtin_constant_p(x) ? x : 1];],
171+
[],
172+
[pgac_cv__builtin_constant_p=yes],
173+
[pgac_cv__builtin_constant_p=no])])
174+
if test x"$pgac_cv__builtin_constant_p" = xyes ; then
175+
AC_DEFINE(HAVE__BUILTIN_CONSTANT_P, 1,
176+
[Define to 1 if your compiler understands __builtin_constant_p.])
177+
fi])# PGAC_C_BUILTIN_CONSTANT_P
178+
179+
180+
181+
# PGAC_C_BUILTIN_UNREACHABLE
182+
# --------------------------
183+
# Check if the C compiler understands __builtin_unreachable(),
184+
# and define HAVE__BUILTIN_UNREACHABLE if so.
185+
#
186+
# NB: Don't get the idea of putting a for(;;); or such before the
187+
# __builtin_unreachable() call. Some compilers would remove it before linking
188+
# and only a warning instead of an error would be produced.
189+
AC_DEFUN([PGAC_C_BUILTIN_UNREACHABLE],
190+
[AC_CACHE_CHECK(for __builtin_unreachable, pgac_cv__builtin_unreachable,
191+
[AC_TRY_LINK([],
192+
[__builtin_unreachable();],
193+
[pgac_cv__builtin_unreachable=yes],
194+
[pgac_cv__builtin_unreachable=no])])
195+
if test x"$pgac_cv__builtin_unreachable" = xyes ; then
196+
AC_DEFINE(HAVE__BUILTIN_UNREACHABLE, 1,
197+
[Define to 1 if your compiler understands __builtin_unreachable.])
198+
fi])# PGAC_C_BUILTIN_UNREACHABLE
199+
200+
201+
202+
# PGAC_C_VA_ARGS
203+
# --------------
204+
# Check if the C compiler understands C99-style variadic macros,
205+
# and define HAVE__VA_ARGS if so.
206+
AC_DEFUN([PGAC_C_VA_ARGS],
207+
[AC_CACHE_CHECK(for __VA_ARGS__, pgac_cv__va_args,
208+
[AC_TRY_COMPILE([#include <stdio.h>],
209+
[#define debug(...) fprintf(stderr, __VA_ARGS__)
210+
debug("%s", "blarg");
211+
],
212+
[pgac_cv__va_args=yes],
213+
[pgac_cv__va_args=no])])
214+
if test x"$pgac_cv__va_args" = xyes ; then
215+
AC_DEFINE(HAVE__VA_ARGS, 1,
216+
[Define to 1 if your compiler understands __VA_ARGS__ in macros.])
217+
fi])# PGAC_C_VA_ARGS
218+
219+
220+
164221
# PGAC_PROG_CC_CFLAGS_OPT
165222
# -----------------------
166223
# Given a string, check if the compiler supports the string as a

configure

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15659,6 +15659,184 @@ cat >>confdefs.h <<\_ACEOF
1565915659
#define HAVE__BUILTIN_TYPES_COMPATIBLE_P 1
1566015660
_ACEOF
1566115661

15662+
fi
15663+
{ $as_echo "$as_me:$LINENO: checking for __builtin_constant_p" >&5
15664+
$as_echo_n "checking for __builtin_constant_p... " >&6; }
15665+
if test "${pgac_cv__builtin_constant_p+set}" = set; then
15666+
$as_echo_n "(cached) " >&6
15667+
else
15668+
cat >conftest.$ac_ext <<_ACEOF
15669+
/* confdefs.h. */
15670+
_ACEOF
15671+
cat confdefs.h >>conftest.$ac_ext
15672+
cat >>conftest.$ac_ext <<_ACEOF
15673+
/* end confdefs.h. */
15674+
static int x; static int y[__builtin_constant_p(x) ? x : 1];
15675+
int
15676+
main ()
15677+
{
15678+
15679+
;
15680+
return 0;
15681+
}
15682+
_ACEOF
15683+
rm -f conftest.$ac_objext
15684+
if { (ac_try="$ac_compile"
15685+
case "(($ac_try" in
15686+
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
15687+
*) ac_try_echo=$ac_try;;
15688+
esac
15689+
eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
15690+
$as_echo "$ac_try_echo") >&5
15691+
(eval "$ac_compile") 2>conftest.er1
15692+
ac_status=$?
15693+
grep -v '^ *+' conftest.er1 >conftest.err
15694+
rm -f conftest.er1
15695+
cat conftest.err >&5
15696+
$as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
15697+
(exit $ac_status); } && {
15698+
test -z "$ac_c_werror_flag" ||
15699+
test ! -s conftest.err
15700+
} && test -s conftest.$ac_objext; then
15701+
pgac_cv__builtin_constant_p=yes
15702+
else
15703+
$as_echo "$as_me: failed program was:" >&5
15704+
sed 's/^/| /' conftest.$ac_ext >&5
15705+
15706+
pgac_cv__builtin_constant_p=no
15707+
fi
15708+
15709+
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
15710+
fi
15711+
{ $as_echo "$as_me:$LINENO: result: $pgac_cv__builtin_constant_p" >&5
15712+
$as_echo "$pgac_cv__builtin_constant_p" >&6; }
15713+
if test x"$pgac_cv__builtin_constant_p" = xyes ; then
15714+
15715+
cat >>confdefs.h <<\_ACEOF
15716+
#define HAVE__BUILTIN_CONSTANT_P 1
15717+
_ACEOF
15718+
15719+
fi
15720+
{ $as_echo "$as_me:$LINENO: checking for __builtin_unreachable" >&5
15721+
$as_echo_n "checking for __builtin_unreachable... " >&6; }
15722+
if test "${pgac_cv__builtin_unreachable+set}" = set; then
15723+
$as_echo_n "(cached) " >&6
15724+
else
15725+
cat >conftest.$ac_ext <<_ACEOF
15726+
/* confdefs.h. */
15727+
_ACEOF
15728+
cat confdefs.h >>conftest.$ac_ext
15729+
cat >>conftest.$ac_ext <<_ACEOF
15730+
/* end confdefs.h. */
15731+
15732+
int
15733+
main ()
15734+
{
15735+
__builtin_unreachable();
15736+
;
15737+
return 0;
15738+
}
15739+
_ACEOF
15740+
rm -f conftest.$ac_objext conftest$ac_exeext
15741+
if { (ac_try="$ac_link"
15742+
case "(($ac_try" in
15743+
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
15744+
*) ac_try_echo=$ac_try;;
15745+
esac
15746+
eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
15747+
$as_echo "$ac_try_echo") >&5
15748+
(eval "$ac_link") 2>conftest.er1
15749+
ac_status=$?
15750+
grep -v '^ *+' conftest.er1 >conftest.err
15751+
rm -f conftest.er1
15752+
cat conftest.err >&5
15753+
$as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
15754+
(exit $ac_status); } && {
15755+
test -z "$ac_c_werror_flag" ||
15756+
test ! -s conftest.err
15757+
} && test -s conftest$ac_exeext && {
15758+
test "$cross_compiling" = yes ||
15759+
$as_test_x conftest$ac_exeext
15760+
}; then
15761+
pgac_cv__builtin_unreachable=yes
15762+
else
15763+
$as_echo "$as_me: failed program was:" >&5
15764+
sed 's/^/| /' conftest.$ac_ext >&5
15765+
15766+
pgac_cv__builtin_unreachable=no
15767+
fi
15768+
15769+
rm -rf conftest.dSYM
15770+
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
15771+
conftest$ac_exeext conftest.$ac_ext
15772+
fi
15773+
{ $as_echo "$as_me:$LINENO: result: $pgac_cv__builtin_unreachable" >&5
15774+
$as_echo "$pgac_cv__builtin_unreachable" >&6; }
15775+
if test x"$pgac_cv__builtin_unreachable" = xyes ; then
15776+
15777+
cat >>confdefs.h <<\_ACEOF
15778+
#define HAVE__BUILTIN_UNREACHABLE 1
15779+
_ACEOF
15780+
15781+
fi
15782+
{ $as_echo "$as_me:$LINENO: checking for __VA_ARGS__" >&5
15783+
$as_echo_n "checking for __VA_ARGS__... " >&6; }
15784+
if test "${pgac_cv__va_args+set}" = set; then
15785+
$as_echo_n "(cached) " >&6
15786+
else
15787+
cat >conftest.$ac_ext <<_ACEOF
15788+
/* confdefs.h. */
15789+
_ACEOF
15790+
cat confdefs.h >>conftest.$ac_ext
15791+
cat >>conftest.$ac_ext <<_ACEOF
15792+
/* end confdefs.h. */
15793+
#include <stdio.h>
15794+
int
15795+
main ()
15796+
{
15797+
#define debug(...) fprintf(stderr, __VA_ARGS__)
15798+
debug("%s", "blarg");
15799+
15800+
;
15801+
return 0;
15802+
}
15803+
_ACEOF
15804+
rm -f conftest.$ac_objext
15805+
if { (ac_try="$ac_compile"
15806+
case "(($ac_try" in
15807+
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
15808+
*) ac_try_echo=$ac_try;;
15809+
esac
15810+
eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
15811+
$as_echo "$ac_try_echo") >&5
15812+
(eval "$ac_compile") 2>conftest.er1
15813+
ac_status=$?
15814+
grep -v '^ *+' conftest.er1 >conftest.err
15815+
rm -f conftest.er1
15816+
cat conftest.err >&5
15817+
$as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
15818+
(exit $ac_status); } && {
15819+
test -z "$ac_c_werror_flag" ||
15820+
test ! -s conftest.err
15821+
} && test -s conftest.$ac_objext; then
15822+
pgac_cv__va_args=yes
15823+
else
15824+
$as_echo "$as_me: failed program was:" >&5
15825+
sed 's/^/| /' conftest.$ac_ext >&5
15826+
15827+
pgac_cv__va_args=no
15828+
fi
15829+
15830+
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
15831+
fi
15832+
{ $as_echo "$as_me:$LINENO: result: $pgac_cv__va_args" >&5
15833+
$as_echo "$pgac_cv__va_args" >&6; }
15834+
if test x"$pgac_cv__va_args" = xyes ; then
15835+
15836+
cat >>confdefs.h <<\_ACEOF
15837+
#define HAVE__VA_ARGS 1
15838+
_ACEOF
15839+
1566215840
fi
1566315841
{ $as_echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5
1566415842
$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; }

configure.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,9 @@ AC_C_VOLATILE
11061106
PGAC_C_FUNCNAME_SUPPORT
11071107
PGAC_C_STATIC_ASSERT
11081108
PGAC_C_TYPES_COMPATIBLE
1109+
PGAC_C_BUILTIN_CONSTANT_P
1110+
PGAC_C_BUILTIN_UNREACHABLE
1111+
PGAC_C_VA_ARGS
11091112
PGAC_STRUCT_TIMEZONE
11101113
PGAC_UNION_SEMUN
11111114
PGAC_STRUCT_SOCKADDR_UN

contrib/cube/cubescan.l

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@
1111

1212
/* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
1313
#undef fprintf
14-
#define fprintf(file, fmt, msg) ereport(ERROR, (errmsg_internal("%s", msg)))
14+
#define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg)
15+
16+
static void
17+
fprintf_to_ereport(const char *fmt, const char *msg)
18+
{
19+
ereport(ERROR, (errmsg_internal("%s", msg)));
20+
}
1521

1622
/* Handles to the buffer that the lexer uses internally */
1723
static YY_BUFFER_STATE scanbufhandle;

contrib/seg/segscan.l

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@
1010

1111
/* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
1212
#undef fprintf
13-
#define fprintf(file, fmt, msg) ereport(ERROR, (errmsg_internal("%s", msg)))
13+
#define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg)
14+
15+
static void
16+
fprintf_to_ereport(const char *fmt, const char *msg)
17+
{
18+
ereport(ERROR, (errmsg_internal("%s", msg)));
19+
}
1420

1521
/* Handles to the buffer that the lexer uses internally */
1622
static YY_BUFFER_STATE scanbufhandle;

src/backend/bootstrap/bootscanner.l

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,13 @@
4242

4343
/* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
4444
#undef fprintf
45-
#define fprintf(file, fmt, msg) ereport(ERROR, (errmsg_internal("%s", msg)))
45+
#define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg)
46+
47+
static void
48+
fprintf_to_ereport(const char *fmt, const char *msg)
49+
{
50+
ereport(ERROR, (errmsg_internal("%s", msg)));
51+
}
4652

4753

4854
static int yyline = 1; /* line number for error reporting */

src/backend/parser/scan.l

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,13 @@
4242

4343
/* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
4444
#undef fprintf
45-
#define fprintf(file, fmt, msg) ereport(ERROR, (errmsg_internal("%s", msg)))
45+
#define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg)
46+
47+
static void
48+
fprintf_to_ereport(const char *fmt, const char *msg)
49+
{
50+
ereport(ERROR, (errmsg_internal("%s", msg)));
51+
}
4652

4753
/*
4854
* GUC variables. This is a DIRECT violation of the warning given at the

src/backend/replication/repl_scanner.l

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@
1919

2020
/* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
2121
#undef fprintf
22-
#define fprintf(file, fmt, msg) ereport(ERROR, (errmsg_internal("%s", msg)))
22+
#define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg)
23+
24+
static void
25+
fprintf_to_ereport(const char *fmt, const char *msg)
26+
{
27+
ereport(ERROR, (errmsg_internal("%s", msg)));
28+
}
2329

2430
/* Handle to the buffer that the lexer uses internally */
2531
static YY_BUFFER_STATE scanbufhandle;

src/include/c.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,18 @@ typedef NameData *Name;
748748
#endif /* HAVE__BUILTIN_TYPES_COMPATIBLE_P */
749749

750750

751+
/*
752+
* Mark a point as unreachable in a portable fashion. This should preferably
753+
* be something that the compiler understands, to aid code generation.
754+
* In assert-enabled builds, we prefer abort() for debugging reasons.
755+
*/
756+
#if defined(HAVE__BUILTIN_UNREACHABLE) && !defined(USE_ASSERT_CHECKING)
757+
#define pg_unreachable() __builtin_unreachable()
758+
#else
759+
#define pg_unreachable() abort()
760+
#endif
761+
762+
751763
/*
752764
* Function inlining support -- Allow modules to define functions that may be
753765
* inlined, if the compiler supports it.

src/include/pg_config.h.in

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,12 +635,21 @@
635635
/* Define to 1 if you have the <winldap.h> header file. */
636636
#undef HAVE_WINLDAP_H
637637

638+
/* Define to 1 if your compiler understands __builtin_constant_p. */
639+
#undef HAVE__BUILTIN_CONSTANT_P
640+
638641
/* Define to 1 if your compiler understands __builtin_types_compatible_p. */
639642
#undef HAVE__BUILTIN_TYPES_COMPATIBLE_P
640643

644+
/* Define to 1 if your compiler understands __builtin_unreachable. */
645+
#undef HAVE__BUILTIN_UNREACHABLE
646+
641647
/* Define to 1 if your compiler understands _Static_assert. */
642648
#undef HAVE__STATIC_ASSERT
643649

650+
/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
651+
#undef HAVE__VA_ARGS
652+
644653
/* Define to the appropriate snprintf format for 64-bit ints. */
645654
#undef INT64_FORMAT
646655

0 commit comments

Comments
 (0)