GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — failed to expand BOOST_MPL_AUX_NA_SPEC, Wrong number of parameters for macro BOOST_PP_TUPLE_ELEM · Issue #159 · cppcheck-opensource/simplecpp

failed to expand BOOST_MPL_AUX_NA_SPEC, Wrong number of parameters for macro BOOST_PP_TUPLE_ELEM #159

New issue
Copy link
New issue
Copy link
Open
Open
failed to expand BOOST_MPL_AUX_NA_SPEC, Wrong number of parameters for macro BOOST_PP_TUPLE_ELEM#159
Copy link

Description

@gdsotirov
gdsotirov
opened on Mar 14, 2019
Issue body actions

I wasn't sure whether to report this here or in cppcheck project, so please excuse me if I chose the wrong place.

I stumbled upon the following problem when running cppcheck 1.87 on a C++ source using Boost libraries:

[/usr/include/boost/preprocessor/arithmetic/sub.hpp:47]: (error) failed to expand 'BOOST_MPL_AUX_NA_SPEC', Wrong number of parameters for macro 'BOOST_PP_TUPLE_ELEM'.

I checked this post in the forum, but the error message is not exactly the same. I guess it changed after the fix of #125, but issue #126 is still open and I think #108 is also related to the problem, because the problematic Boost header include/boost/preprocessor/arithmetic/sub.hpp uses ## operator.

Can I somehow workaround the problem until it's fixed in a new cppcheck version?

Activity

  1. danmar commented on Mar 14, 2019

    @danmar
    danmar
    on Mar 14, 2019
    Collaborator
    More actions

    I wasn't sure whether to report this here or in cppcheck project, so please excuse me if I chose the wrong place.

    I don't know. If the "cppcheck -E" output looks wrong then it should be reported here. We can keep the issue here for now.

    Can I somehow workaround the problem until it's fixed in a new cppcheck version?

    Yes certainly.

    In one project there is a workaround for boost macro problems. The project has this define:

    #define VARS_TO_NAMES_AND_VARS(...) \
    BOOST_PP_SEQ_FOR_EACH_I(VAR_TO_STRING_COMMA_VAR, % %, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
    

    Cppcheck does not handle this code well.

    To workaround this the code was updated to:

    #ifndef __cppcheck__
    /// @note Cppcheck does not like the syntax `% %` used here and reports a syntax error if that is seen in analysis.
    /// Maybe someday Cppcheck will have a boost configuration that we can use instead of this ifndef
    #define VARS_TO_NAMES_AND_VARS(...) \
        BOOST_PP_SEQ_FOR_EACH_I(VAR_TO_STRING_COMMA_VAR, % %, 
    BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
    #endif
    

    The preprocessor output is correct as far as I have seen but the % % operator usage is very odd and cppcheck does not like that! I think boost uses some magic here to make such weird syntax possible.

    A -D__cppcheck__ is added on the cppcheck command line to activate this workaround.

    So what will happen now after this workaround... whenever the code uses the macro VARS_TO_NAMES_AND_VARS then it can't be expanded. This is no big deal.

  2. gdsotirov commented on Mar 14, 2019

    @gdsotirov
    gdsotirov
    on Mar 14, 2019
    Author
    More actions

    I meantime checked the manual and there (in section Include paths) it's written that "Actually, it is recommended to not give all include paths." and also "... passing standard library headers is highly discouraged because it will result in worse results and longer checking time.", so I'll proceed by passing only project's include paths to cppcheck, instead of all include paths like I was doing before. The issue could be closed.

  3. danmar commented on Mar 15, 2019

    @danmar
    danmar
    on Mar 15, 2019
    Collaborator
    More actions

    so I'll proceed by passing only project's include path to cppcheck

    good!

  4. danmar
    closed this as completedon Mar 15, 2019
  5. Ken-Patrick commented on Jun 26, 2019

    @Ken-Patrick
    Ken-Patrick
    on Jun 26, 2019
    Contributor
    More actions

    Hi,

    I'm having this same issue when including boost headers. For some reason, we ended up having all of our header in the same directory, so now cppcheck finds boost headers and we have the above error (and more I think).

    Is there a way to tell cppcheck to not use headers in headers_directory/boost ? Or can part of it be overridden via configuration ?

    The only thing I can think of is -D<BOOST_INCLUDES_GUARDS> for all the boost files (that we are using), but it sounds ugly.

    Any idea ?

  6. danmar commented on Jun 27, 2019

    @danmar
    danmar
    on Jun 27, 2019
    Collaborator
    More actions

    This preprocessor does not have any option to skip includes.

    I am not sure what you should do.

    You could probably generate the -D<BOOST_INCLUDES_GUARDS> with a script. I would put them in a file that you include with -include=...

    Unless you have lots of files, this might be an option:

    cp -R headers_directory temp
    rm -rf temp/boost
    cppcheck -I temp ...
    

    Maybe adding some option to cppcheck would be ok also. Although I never got this feature request before so others seem to solve it somehow. I like to get inspiration from GCC so do you know if you can skip certain headers in GCC?

  7. Ken-Patrick commented on Jun 27, 2019

    @Ken-Patrick
    Ken-Patrick
    on Jun 27, 2019
    Contributor
    More actions

    Using -include=... is be a good idea, thanks

    Unless you have lots of files, this might be an option: [skip]

    We do, it might still be an option, thanks !

    Maybe adding some option to cppcheck would be ok also. Although I never got this feature request before so others seem to solve it somehow. I like to get inspiration from GCC so do you know if you can skip certain headers in GCC?

    To my knowledge, GCC does not support this "feature" (which, TBH, would be a bit weird for a compiler, if you don't want the include, don't pass -I...), the only thing a bit close is -iquote (which allow to pass some directory that GCC will search first.
    Thinking about it, I can also do something like this: replicate the boost tree, but with empty files, and give this directory first to cppcheck.

    Is it worth trying to fix cppcheck so that I can understand the boost headers ? I have the feeling the it would be painful and that the answer is no.

    We'll probably go for one of the hack we discussed.

  8. danmar commented on Jun 28, 2019

    @danmar
    danmar
    on Jun 28, 2019
    Collaborator
    More actions

    Is it worth trying to fix cppcheck so that I can understand the boost headers ? I have the feeling the it would be painful and that the answer is no.

    That really sounds like a good solution. This is how I would do it personally.. I just thought from a "user" perspective before.

    If this is caused by a problem in simplecpp or cppcheck I think it should be fixed.

  9. Ken-Patrick commented on Jun 28, 2019

    @Ken-Patrick
    Ken-Patrick
    on Jun 28, 2019
    Contributor
    More actions

    Ok. I might give it a try (and I'll probably die in the middle because of all the preprocessing stuff that I won't understand :p).

  10. Ken-Patrick commented on Jun 29, 2019

    @Ken-Patrick
    Ken-Patrick
    on Jun 29, 2019
    Contributor
    More actions

    I've found something:
    Inside expandHashHash, (or expandArg ?), in some cases a '(' is appended to a token name, for instance strAB becomes for instance "BOOST_PP_IIF_I(" (there are many of them, and I don't have a small test case, so I don't know which one exactly causes the pb. Any way, they all seem wrong).
    I guess this happens when simplecpp is trying to expand ##( or something that was expanded to ##(.

    Then, getMacroParameters is confused and in
    https://github.com/boostorg/preprocessor/blob/develop/include/boost/preprocessor/arithmetic/sub.hpp#L47

    # define BOOST_PP_SUB_D_I(d, x, y) BOOST_PP_TUPLE_ELEM(2, 0, BOOST_PP_WHILE_ ## d(BOOST_PP_SUB_P, BOOST_PP_SUB_O, (x, y)))
    

    it believes BOOST_PP_TUPLE_ELEM is called with 6 parameters, hence the error.

    The following fixes the issue. I've close to no idea what I am doing here, so it's probably not the right fix. I hope it gives you enough insight so that we can work out the right fix.

    --- a/simplecpp.cpp
    +++ b/simplecpp.cpp
    @@ -1719,6 +1719,9 @@ namespace simplecpp {
                 if (variadic && argnr + 1U >= parametertokens.size())
                     return true;
     
    +            if (parametertokens[argnr]->next->op == '(')
    +                return false;
    +
                 for (const Token *partok = parametertokens[argnr]->next; partok != parametertokens[argnr + 1U]; partok = partok->next)
                     output->push_back(new Token(*partok));
     
    
    
  11. danmar commented on Jun 29, 2019

    @danmar
    danmar
    on Jun 29, 2019
    Collaborator
    More actions

    hmm.. that is interesting. The fix does not look wrong but I think I want to investigate this also. A short code example that reproduce the problem would be awesome!

  12. danmar commented on Jun 29, 2019

    @danmar
    danmar
    on Jun 29, 2019
    Collaborator
    More actions

    can I reproduce somehow? Is it enough to include some boost header and write some code?

  13. Ken-Patrick commented on Jun 29, 2019

    @Ken-Patrick
    Ken-Patrick
    on Jun 29, 2019
    Contributor
    More actions

    I believe including #include <boost/foreach.hpp> or boost/config.hpp is enough (I have not really tested though /o).

    Then there are other issues, in https://www.boost.org/doc/libs/1_52_0/boost/type_traits/detail/cv_traits_impl.hpp
    the preprocessing of

    #if !(BOOST_WORKAROUND(__GNUC__,== 3) && BOOST_WORKAROUND(__GNUC_MINOR__, <= 2))
    

    goes wrong, then the evaluation also, and it defaults to 0.
    Then in the same file, same thing with

    #if BOOST_WORKAROUND(__GNUC__,== 3) && BOOST_WORKAROUND(__GNUC_MINOR__, <= 2)
    

    and we end up with an extra '{', and the parsing fails with an error.

    Then, some boost files (at least cstdint.hpp) expects some constants defined b standard headers (things like UCHAR_MAX, UINT_MAX, etc).

    I stopped there and will make cppcheck ignore these files (either playing with -DBOOST... and --include, or removing the file).

    It might even make sense to ignore boost in simplecpp:

    --- a/simplecpp.cpp
    +++ b/simplecpp.cpp
    @@ -2440,6 +2443,9 @@ std::map<std::string, simplecpp::TokenList*> simplecpp::load(const simplecpp::To
             if (hasFile(ret, sourcefile, header, dui, systemheader))
                 continue;
    
    +        if (header.rfind("boost/", 0) == 0)
    +            continue;
    +
             std::ifstream f;
             const std::string header2 = openHeader(f,dui,sourcefile,header,systemheader);
             if (!f.is_open())
    
    
  14. danmar commented on Jun 30, 2019

    @danmar
    danmar
    on Jun 30, 2019
    Collaborator
    More actions

    I believe including #include <boost/foreach.hpp> or boost/config.hpp is enough (I have not really tested though /o).

    ok.. when I include foreach.hpp I get this error message from simplecpp:

    ../include/boost_1_69_0/boost/preprocessor/logical/bool.hpp:24: syntax error: failed to expand 'BOOST_MPL_AUX_NA_SPEC', Wrong number of parameters for macro 'BOOST_PP_BOOL_OO'.
    

    Sounds like your problem.

  15. danmar commented on Jul 1, 2019

    @danmar
    danmar
    on Jul 1, 2019
    Collaborator
    More actions

    Here is a reduced code:

    
    
    # define BOOST_PP_CONFIG_STRICT() 0x0001
    # define BOOST_PP_CONFIG_MSVC() 0x0004
    # define BOOST_PP_CONFIG_MWCC() 0x0008
    # define BOOST_PP_CONFIG_BCC() 0x0010
    # define BOOST_PP_CONFIG_EDG() 0x0020
    # define BOOST_PP_CONFIG_DMC() 0x0040
    # define BOOST_PP_CONFIG_FLAGS() (BOOST_PP_CONFIG_STRICT())
    
    #define BOOST_PP_CAT(a, b)        BOOST_PP_CAT_I(a, b)
    #define BOOST_PP_CAT_I(a, b)      a ## b
    
    
    # if ~BOOST_PP_CONFIG_FLAGS() & BOOST_PP_CONFIG_MWCC()
    #    define BOOST_PP_IIF(bit, t, f) BOOST_PP_IIF_I(bit, t, f)
    # else
    #    define BOOST_PP_IIF(bit, t, f) BOOST_PP_IIF_OO((bit, t, f))
    #    define BOOST_PP_IIF_OO(par) BOOST_PP_IIF_I ## par
    # endif
    
    
    # define BOOST_PP_AUTO_REC(pred, n)  BOOST_PP_NODE_ENTRY_ ## n(pred)
    # define BOOST_PP_NODE_ENTRY_256(p)  BOOST_PP_NODE_128(p)(p)(p)(p)(p)(p)(p)(p)
    # define BOOST_PP_NODE_ENTRY_128(p)  BOOST_PP_NODE_64(p)(p)(p)(p)(p)(p)(p)
    # define BOOST_PP_NODE_128(p)        BOOST_PP_IIF(p(128), BOOST_PP_NODE_64, BOOST_PP_NODE_192)
    # define BOOST_PP_NODE_64(p)         BOOST_PP_IIF(p(64), BOOST_PP_NODE_32, BOOST_PP_NODE_96)
    
    
    
    #define BOOST_PP_WHILE BOOST_PP_CAT(BOOST_PP_WHILE_, BOOST_PP_AUTO_REC(BOOST_PP_WHILE_P, 256))
    #define BOOST_PP_WHILE_P(n) BOOST_PP_BITAND(BOOST_PP_CAT(BOOST_PP_WHILE_CHECK_, BOOST_PP_WHILE_ ## n(BOOST_PP_WHILE_F, BOOST_PP_NIL, BOOST_PP_NIL)), BOOST_PP_CAT(BOOST_PP_LIST_FOLD_LEFT_CHECK_, BOOST_PP_LIST_FOLD_LEFT_ ## n(BOOST_PP_NIL, BOOST_PP_NIL, BOOST_PP_NIL)))
    # define BOOST_PP_WHILE_F(d, _) 0
    
    
    
    
    #define BOOST_PP_SUB(x, y)        BOOST_PP_SUB_I(x, y)
    #define BOOST_PP_SUB_I(x, y)      BOOST_PP_TUPLE_ELEM(2, 0, BOOST_PP_WHILE(BOOST_PP_SUB_P, BOOST_PP_SUB_O, (x, y)))
    # define BOOST_PP_SUB_P(d, xy)    BOOST_PP_TUPLE_ELEM(2, 1, xy)
    
    
    #define BOOST_MPL_PP_SUB(i,j)       BOOST_PP_SUB(i,j)
    
    #   define BOOST_MPL_PP_DEF_PARAMS_TAIL_IMPL(i, param, value_func) \
        BOOST_MPL_PP_DEF_PARAMS_TAIL_DELAY_1( \
              i \
            , BOOST_MPL_PP_SUB(BOOST_MPL_LIMIT_METAFUNCTION_ARITY,i) \
            , param \
            , value_func \
            )
    
    #define BOOST_MPL_PP_DEF_PARAMS_TAIL(i, param, value) \
        BOOST_MPL_PP_DEF_PARAMS_TAIL_IMPL(i, param, BOOST_PP_IDENTITY(=value))
    
    
    #   define BOOST_MPL_PP_NESTED_DEF_PARAMS_TAIL(i, param, value) \
        BOOST_MPL_PP_DEF_PARAMS_TAIL_IMPL(i, param, BOOST_PP_IDENTITY(=value))
    
    
    #define BOOST_MPL_AUX_NA_SPEC_MAIN(i, name)     BOOST_MPL_AUX_NA_PARAMS(i) > \
            BOOST_MPL_PP_NESTED_DEF_PARAMS_TAIL(i, typename T, na) \
            BOOST_MPL_PP_PARAMS(i, T)
    
    #define BOOST_MPL_AUX_NA_SPEC_NO_ETI(i, name)    BOOST_MPL_AUX_NA_SPEC_MAIN(i, name)
    #define BOOST_MPL_AUX_NA_SPEC(i, name)           BOOST_MPL_AUX_NA_SPEC_NO_ETI(i, name)
    
    BOOST_MPL_AUX_NA_SPEC(3, if_)
    

    I hope it can be reduced further.

    But with gcc -E I get no preprocessor error. Simplecpp writes an error for this code:

     159.cpp:11: syntax error: failed to expand 'BOOST_MPL_AUX_NA_SPEC', Wrong number of parameters for macro 'BOOST_PP_CAT_I'.
    

    I am not sure but I have the feeling the #if condition is not calculated properly in simplecpp.

    I hope this code that I inserted can be reduced to ~ 2-5 lines

  16. danmar commented on Jul 3, 2019

    @danmar
    danmar
    on Jul 3, 2019
    Collaborator
    More actions

    @Ken-Patrick Can you try with the latest changes. After 229d41f , simplecpp seems to preprocess this code fine:

    #include <boost/foreach.hpp>
    
  17. SpareSimian commented on Aug 3, 2021

    @SpareSimian
    SpareSimian
    on Aug 3, 2021
    More actions

    I ran into a similar issue with the wxWidgets macros that create a path for an include directive and found this similar bug report.

    My code (extracted from wx's setup.h and cpp.h) reproducing the problem using cppcheck:

    // simulate wx setup.h/cpp.h macros
    #define wxCONCAT_HELPER(text, line) text ## line
    #define wxCONCAT(x1, x2) \
        wxCONCAT_HELPER(x1, x2)
    #define wxCONCAT3(x1, x2, x3) \
        wxCONCAT(wxCONCAT(x1, x2), x3)
    #define wxCONCAT4(x1, x2, x3, x4) \
        wxCONCAT(wxCONCAT3(x1, x2, x3), x4)
    #define wxCONCAT5(x1, x2, x3, x4, x5) \
        wxCONCAT(wxCONCAT4(x1, x2, x3, x4), x5)
    #define wxCONCAT6(x1, x2, x3, x4, x5, x6) \
        wxCONCAT(wxCONCAT5(x1, x2, x3, x4, x5), x6)
    #define wxCONCAT7(x1, x2, x3, x4, x5, x6, x7) \
        wxCONCAT(wxCONCAT6(x1, x2, x3, x4, x5, x6), x7)
    /* wxSTRINGIZE works as the preprocessor # operator but also works with macros */
    #define wxSTRINGIZE_HELPER(x)       #x
    #define wxSTRINGIZE(x)              wxSTRINGIZE_HELPER(x)
    #define wxCOMPILER_PREFIX vc142
    #define wxARCH_SUFFIX _x64
    #define wxCFG
    #define wxLIB_SUBDIR \
        wxCONCAT4(wxCOMPILER_PREFIX, wxARCH_SUFFIX, _lib, wxCFG)
    #define wxTOOLKIT_PREFIX msw
    #define wxSUFFIX ud
    #define wxSETUPH_PATH \
        wxCONCAT6(../../../lib/, wxLIB_SUBDIR, /, wxTOOLKIT_PREFIX, wxSUFFIX, /wx/setup.h)
    #define wxSETUPH_PATH_STR wxSTRINGIZE(wxSETUPH_PATH)
    #include wxSETUPH_PATH_STR
    
  18. danmar commented on Aug 4, 2021

    @danmar
    danmar
    on Aug 4, 2021
    Collaborator
    More actions

    @SpareSimian can you please try to create some little code sample I can test locally with simplecpp? and then please report it in a new issue.

    I assume the code you show is supposed to include some file but it's not easy to manually see which file..

  19. SpareSimian commented on Aug 4, 2021

    @SpareSimian
    SpareSimian
    on Aug 4, 2021
    More actions

    Put the above sample in a .cpp file and cppcheck throws an error. It's trying to compute a string that looks like "../../../lib/vc142_x64_lib/mswud/setup.h".

    I copied the above into token_concat.cpp, loaded a clone of master into Visual Studio 2019, and got this:

    f:\devel\simplecpp\out\build\x64-Debug>.\simplecpp.exe token_concat.cpp 
    
    token_concat.cpp:2: syntax error: failed to expand 'wxSETUPH_PATH_STR', Invalid ## usage when expanding 'wxCONCAT_HELPER'.
    
  20. SpareSimian commented on Aug 4, 2021

    @SpareSimian
    SpareSimian
    on Aug 4, 2021
    More actions

    You can replace the include directive with this to make it easier to see. I can reproduce it in the debugger in Visual Studio but I'm not familiar enough with the code to see how it fails. The final token is ")", though.

    static const char path[] = wxSETUPH_PATH_STR;

  21. SpareSimian commented on Aug 4, 2021

    @SpareSimian
    SpareSimian
    on Aug 4, 2021
    More actions

    I managed to shrink the failing sample down to this:

    #define wxCONCAT(text1, text2)       text1 ## text2
    #define wxCONCAT3(x1, x2, x3)       wxCONCAT(wxCONCAT(x1, x2), x3)
    #define wxSETUPH_PATH               wxCONCAT3(vc142, _x64, _lib)
    extern int wxSETUPH_PATH;
    
  22. danmar commented on Aug 4, 2021

    @danmar
    danmar
    on Aug 4, 2021
    Collaborator
    More actions

    great! can you please create a new issue with that code.

    Reacted by SpareSimian
  23. marek22k commented on Mar 14, 2024

    @marek22k
    marek22k
    on Mar 14, 2024
    More actions

    Hi, I am running cppcheck with meson and have also encountered this false positive error. While searching for it on the internet I landed on this issue here. Has the error already been forwarded to cppcheck?

  24. danmar commented on Sep 29, 2024

    @danmar
    danmar
    on Sep 29, 2024
    Collaborator
    More actions

    I reopen this issue because people still have problems we'll need to solve it properly.

  25. danmar
    reopened this on Sep 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.