> On 27/01/2017, at 9:09 PM, Kim Gräsman <kim.gras...@gmail.com> wrote:
> 
> On Thu, Jan 26, 2017 at 10:08 PM, David Empson <demp...@emptech.co.nz 
> <mailto:demp...@emptech.co.nz>> wrote:
>> 
>>> On 26/01/2017, at 8:46 PM, Clemens Ladisch <clem...@ladisch.de> wrote:
>>> 
>>>> …
>>>>  {"icu_load_collation",  2, SQLITE_UTF8, (void*)db, icuLoadCollation},
>>>> };
>> 
>> The ANSI/ISO C 1990 standard states this in section 6.5.7, under Constraints:
>> 
>> “All the expressions in an initializer for an object that has static storage 
>> duration or in an initializer list for an object that has aggregate or union 
>> type shall be constant expressions.”
> 
> But this object doesn't have static storage duration, does it?
> `scalars` is just a local variable in a function:
> https://sourcecodebrowser.com/sqlite3/3.6.21/icu_8c_source.html#l00449 
> <https://sourcecodebrowser.com/sqlite3/3.6.21/icu_8c_source.html#l00449>
> 
> unless I'm looking at the wrong version.

That version does have the text quoted above.

The problem is that ANSI/ISO C 1990 stipulates that an initializer for any 
object of aggregate type, whether or not it is static, must be constant.

It doesn’t matter that this variable has auto storage - it is an aggregate type 
(array of structs), and the initializer for an aggregate type must be constant 
if a compiler is enforcing ANSI/ISO C 1990 rules (or is based on C90 but hasn’t 
implemented extensions to allow a non-constant initializer for an aggregate 
type).

As I noted, C99 changed the rules and does allow a non-constant initializer in 
this case.

The code in question has been there since May 2007, so the fact that nobody 
reported it until now suggests that almost nobody who uses the ICU extension is 
doing so with a strict ANSI C90 compiler (or a compiler set to enforce C90 
rules).

Perhaps SQLite’s test procedure should be enforcing strict ANSI C mode? If this 
is already being done, then the compiler(s) used might not be enforcing this 
particular rule.

> Again, it would be nice to see the actual warning from MSVC.

Indeed.

As it happens, I have an installation of Visual C++ 2008 so can test this, not 
using icu.c as I don’t have necessary support files installed, but I can create 
a mockup using a copy of the sqlite3IcuInit function with stubs for everything 
it references.

Using default options from the command line, my test file compiles without 
error.

Therefore Visual C++ 2008 does have extensions to ANSI C90 which allow a 
non-constant initializer for an aggregate type with auto storage. (I also 
tested Visual C++ 98 and it worked there too.)

However if I tell Visual C++ to enable strict ANSI C mode by adding the /Za 
command line option, I get an error:


[C:\p\test]cl /Za test.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

test.c
test.c(45) : error C2097: illegal initialization


This is consistent with the rule I noted from ANSI/ISO C 1990.

For reference, here is my test.c:


typedef struct { int a; } sqlite3;
typedef struct { int b; } sqlite3_context;
typedef struct { int c; } sqlite3_value;

#define SQLITE_ANY                              1
#define SQLITE_DETERMINISTIC    2
#define SQLITE_UTF16                    4
#define SQLITE_UTF8                             8

#define SQLITE_OK                               0

void icuRegexpFunc(sqlite3_context*c, int i, sqlite3_value**vpp) { }
void icuCaseFunc16(sqlite3_context*c, int i, sqlite3_value**vpp) { }
void icuLikeFunc(sqlite3_context*c, int i, sqlite3_value**vpp) { }
void icuLoadCollation(sqlite3_context*c, int i, sqlite3_value**vpp) { }

int sqlite3_create_function(sqlite3 *db, const char *zName, int nArg, int enc, 
void *pContext,
                                                        void 
(*xFunc)(sqlite3_context*,int,sqlite3_value**), int i, int j) {
  return SQLITE_OK;
}

int sqlite3IcuInit(sqlite3 *db){
  struct IcuScalar {
    const char *zName;                        /* Function name */
    int nArg;                                 /* Number of arguments */
    int enc;                                  /* Optimal text encoding */
    void *pContext;                           /* sqlite3_user_data() context */
    void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
  } scalars[] = {
    {"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC,          0, icuRegexpFunc},

    {"lower",  1, SQLITE_UTF16|SQLITE_DETERMINISTIC,        0, icuCaseFunc16},
    {"lower",  2, SQLITE_UTF16|SQLITE_DETERMINISTIC,        0, icuCaseFunc16},
    {"upper",  1, SQLITE_UTF16|SQLITE_DETERMINISTIC, (void*)1, icuCaseFunc16},
    {"upper",  2, SQLITE_UTF16|SQLITE_DETERMINISTIC, (void*)1, icuCaseFunc16},

    {"lower",  1, SQLITE_UTF8|SQLITE_DETERMINISTIC,         0, icuCaseFunc16},
    {"lower",  2, SQLITE_UTF8|SQLITE_DETERMINISTIC,         0, icuCaseFunc16},
    {"upper",  1, SQLITE_UTF8|SQLITE_DETERMINISTIC,  (void*)1, icuCaseFunc16},
    {"upper",  2, SQLITE_UTF8|SQLITE_DETERMINISTIC,  (void*)1, icuCaseFunc16},

    {"like",   2, SQLITE_UTF8|SQLITE_DETERMINISTIC,         0, icuLikeFunc},
    {"like",   3, SQLITE_UTF8|SQLITE_DETERMINISTIC,         0, icuLikeFunc},

    {"icu_load_collation",  2, SQLITE_UTF8, (void*)db, icuLoadCollation},
  };

  int rc = SQLITE_OK;
  int i;

  for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){
    struct IcuScalar *p = &scalars[i];
    rc = sqlite3_create_function(
        db, p->zName, p->nArg, p->enc, p->pContext, p->xFunc, 0, 0
    );
  }

  return rc;
}

int main(void) {
  sqlite3 db;
  return sqlite3IcuInit(&db);
}


_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to