mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-05 02:36:19 +01:00
gstrfuncs: Improve inline version of g_strdup() to avoid breaking C++ code
Wrap the logic into a G_ALWAYS_INLINE function, instead of using a complex statement-expression which is not allowed in braced initializer lists and expanded into some bad thing when it's used as `::g_strdup(...)`. We cannot use `__builtin_constant_p (str)` because GCC documentation clearly states that it always produces 0 when str is a const char * argument of an inline function. But `__builtin_constant_p (!str)`, `__builtin_constant_p (!!str)`, and `__builtin_constant_p (strlen (str))` functions properly with `-O1` or above enabled. Fixes #2936.
This commit is contained in:
parent
ed256d6447
commit
cc7f2f81cc
@ -204,23 +204,6 @@ gboolean (g_str_has_prefix) (const gchar *str,
|
||||
(g_str_has_suffix) (STR, SUFFIX) \
|
||||
)
|
||||
|
||||
#define g_strdup(STR) \
|
||||
(__builtin_constant_p ((STR)) ? \
|
||||
(G_LIKELY ((STR) != NULL) ? \
|
||||
G_GNUC_EXTENSION ({ \
|
||||
const char *const ___str = ((STR)); \
|
||||
const char *const __str = _G_STR_NONNULL (___str); \
|
||||
const size_t __str_len = strlen (__str) + 1; \
|
||||
char *__dup_str = (char *) g_malloc (__str_len); \
|
||||
(char *) memcpy (__dup_str, __str, __str_len); \
|
||||
}) \
|
||||
: \
|
||||
(char *) (NULL) \
|
||||
) \
|
||||
: \
|
||||
(g_strdup) ((STR)) \
|
||||
)
|
||||
|
||||
#endif /* !defined (__GI_SCANNER__) */
|
||||
#endif /* !defined (__GTK_DOC_IGNORE__) */
|
||||
#endif /* G_GNUC_CHECK_VERSION (2, 0) */
|
||||
@ -318,6 +301,32 @@ GLIB_AVAILABLE_IN_ALL
|
||||
gchar* g_strjoin (const gchar *separator,
|
||||
...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED;
|
||||
|
||||
#if G_GNUC_CHECK_VERSION(2, 0)
|
||||
#ifndef __GTK_DOC_IGNORE__
|
||||
#ifndef __GI_SCANNER__
|
||||
|
||||
G_ALWAYS_INLINE static inline char *
|
||||
g_strdup_inline (const char *str)
|
||||
{
|
||||
if (__builtin_constant_p (!str) && !str)
|
||||
return NULL;
|
||||
|
||||
if (__builtin_constant_p (!!str) && !!str && __builtin_constant_p (strlen (str)))
|
||||
{
|
||||
const size_t len = strlen (str) + 1;
|
||||
char *dup_str = (char *) g_malloc (len);
|
||||
return (char *) memcpy (dup_str, str, len);
|
||||
}
|
||||
|
||||
return g_strdup (str);
|
||||
}
|
||||
|
||||
#define g_strdup(x) g_strdup_inline (x)
|
||||
|
||||
#endif /* !defined (__GI_SCANNER__) */
|
||||
#endif /* !defined (__GTK_DOC_IGNORE__) */
|
||||
#endif /* G_GNUC_CHECK_VERSION (2, 0) */
|
||||
|
||||
/* Make a copy of a string interpreting C string -style escape
|
||||
* sequences. Inverse of g_strescape. The recognized sequences are \b
|
||||
* \f \n \r \t \\ \" and the octal format.
|
||||
|
@ -349,6 +349,36 @@ test_strdup_macro (void)
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
static void
|
||||
test_strdup_macro_qualified (void)
|
||||
{
|
||||
gchar *str;
|
||||
|
||||
g_assert_null (::g_strdup (NULL));
|
||||
|
||||
str = ::g_strdup ("C++ is cool too!");
|
||||
g_assert_nonnull (str);
|
||||
g_assert_cmpstr (str, ==, "C++ is cool too!");
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
static void
|
||||
test_strdup_macro_nested_initializer (void)
|
||||
{
|
||||
struct
|
||||
{
|
||||
char *p, *q;
|
||||
} strings = {
|
||||
g_strdup (NULL),
|
||||
g_strdup ("C++ is cool too!"),
|
||||
};
|
||||
|
||||
g_assert_null (strings.p);
|
||||
g_assert_nonnull (strings.q);
|
||||
g_assert_cmpstr (strings.q, ==, "C++ is cool too!");
|
||||
g_free (strings.q);
|
||||
}
|
||||
|
||||
static void
|
||||
test_str_has_prefix (void)
|
||||
{
|
||||
@ -527,6 +557,8 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/C++/str-equal", test_str_equal);
|
||||
g_test_add_func ("/C++/strdup", test_strdup);
|
||||
g_test_add_func ("/C++/strdup/macro", test_strdup_macro);
|
||||
g_test_add_func ("/C++/strdup/macro/qualified", test_strdup_macro_qualified);
|
||||
g_test_add_func ("/C++/strdup/macro/nested-initializer", test_strdup_macro_nested_initializer);
|
||||
g_test_add_func ("/C++/str-has-prefix", test_str_has_prefix);
|
||||
g_test_add_func ("/C++/str-has-prefix/macro", test_str_has_prefix_macro);
|
||||
g_test_add_func ("/C++/str-has-suffix", test_str_has_suffix);
|
||||
|
Loading…
Reference in New Issue
Block a user