23

Let us say I've written this C++ program (that essentially is doing nothing)

#include <cstdlib>

int main(int argc, char *argv[]) {
  enum class Color { Red, Orange, Yellow, Green, Blue, Violet };
  constexpr float a = 3.1415f;
  auto b = a;
  return EXIT_SUCCESS;
}

Is there a way to detect which C++11 features that are used in my program? Is there maybe some other program that could extract this information out of my source code? Such a program could output a list of features:

$ cat main.cc | some-clever-software
N2347
N1984
N2235

(Alternatively it could output URL:s http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf instead)

If I had such a list it would be easier to write a CMakeLists.txt that makes use of the CMake command target_compile_features(), such as this one

cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
project(foobar CXX)
add_executable(foobar main.cc)                                                                                                                                                                                                                                                     
set(needed_features
    cxx_strong_enums
    cxx_constexpr
    cxx_auto_type)
target_compile_features(foobar PRIVATE ${needed_features})

The C++11 features that CMake let us choose from are listed in the CMake variable CMAKE_CXX_KNOWN_FEATURES. I know that the CMake command target_compile_features() has not yet been released in a stable CMake release. It currently lives in the development branch so it might come to change in the future. But nevertheless I'm interested if it is possible to detect what C++11 features are used in some C++ source code.

Update:

Compiling without the -std=c++11 compiler option was suggested in a comment:

First compiling with g++

$ g++ --version
g++ (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++ main.cc
main.cc: In function ‘int main(int, char**)’:
main.cc:4:3: warning: scoped enums only available with -std=c++11 or -std=gnu++11 [enabled by default]
   enum class Color { Red, Orange, Yellow, Green, Blue, Violet };
   ^
main.cc:5:3: error: ‘constexpr’ was not declared in this scope
   constexpr float a = 3.1415f;
   ^
main.cc:5:13: error: expected ‘;’ before ‘float’
   constexpr float a = 3.1415f;
             ^
main.cc:6:8: error: ‘b’ does not name a type
   auto b = a;
        ^

and then compiling with clang

$ clang --version
Debian clang version 3.2-7ubuntu1 (tags/RELEASE_32/final) (based on LLVM 3.2)
Target: x86_64-pc-linux-gnu
Thread model: posix
$ clang main.cc
main.cc:4:8: error: expected identifier or '{'
  enum class Color { Red, Orange, Yellow, Green, Blue, Violet };
       ^
main.cc:4:3: warning: declaration does not declare anything [-Wmissing-declarations]
  enum class Color { Red, Orange, Yellow, Green, Blue, Violet };
  ^~~~
main.cc:5:3: error: unknown type name 'constexpr'
  constexpr float a = 3.1415f;
  ^
main.cc:5:13: error: expected unqualified-id
  constexpr float a = 3.1415f;
            ^
main.cc:6:3: warning: 'auto' type specifier is a C++11 extension [-Wc++11-extensions]
  auto b = a;
  ^
main.cc:6:12: error: use of undeclared identifier 'a'
  auto b = a;
           ^
2 warnings and 4 errors generated.
$

Of course, the diagnostics from the compilers give me good hints of which C++11 features that are in use. But what I would like to have is more fine-grained information:

N2235

instead of

error: ‘constexpr’ was not declared in this scope

Erik Sjölund
  • 10,690
  • 7
  • 46
  • 74
  • 15
    Compile without `-std=c++11` compiler option? – πάντα ῥεῖ Apr 13 '14 at 12:33
  • @πάνταῥεῖ I tried out both **g++** and **clang**. Read more about the trials in the updated question. – Erik Sjölund Apr 13 '14 at 13:08
  • 1
    OK, then the better approach instead of grepping the source for features, might be to grep the emitted error messages based on mappings for the various error message formats. Also a decent clang plugin could do based on judging the AST. – πάντα ῥεῖ Apr 13 '14 at 13:11
  • @πάνταῥεῖ I really like the suggestion of writing a clang plugin to analyze the AST. That seems to be the way to go! – Erik Sjölund Apr 13 '14 at 13:24
  • Yeah, I had the idea, since you mentioned clang already ;) ... Mapping error message formats sounds clumsy. – πάντα ῥεῖ Apr 13 '14 at 13:25
  • 4
    Voting to reopen. This is not a request for a favorite too, it's an "is it possible" and "how to" question. – Adrian McCarthy Apr 13 '14 at 14:31
  • 1
    The error message approach also has the disadvantage that it is likely to get the compiler really confused if you compile with a wrong standard, possibly leading to either a bailout or a few megabytes of error messages. Not the kind of stuff you would want to have in a script. – cmaster - reinstate monica Apr 13 '14 at 18:16
  • 1
    So what if there is a sequence of symbols that means **different** things in C++03 than C++11? I fear your goal may be misguided... – Yakk - Adam Nevraumont Apr 13 '14 at 18:40
  • 1
    You must be following the mailing list, so you might as well link to http://www.steveire.com/cmake-future/manual/cmake-compile-features.7.html for information – steveire Apr 13 '14 at 18:47
  • 1
    @Yakk Your comment inspired me to ask http://stackoverflow.com/questions/23047198/can-c-code-be-valid-in-both-c03-and-c11-but-do-different-things – Erik Sjölund Apr 13 '14 at 19:20
  • @steveire I now added a link to http://www.steveire.com/cmake-future/command/target_compile_features.html That web page mentions the link you provided – Erik Sjölund Apr 13 '14 at 19:36
  • 1
    Try with a pre-C++11 compiler? – 3Dave Apr 13 '14 at 19:39
  • @πάνταῥεῖ Sometimes error can give you the desired outcome, like in SQLI :) – 0x90 Apr 13 '14 at 20:11
  • @0x90 Yes, and what? I don't get your comment referring to mine?!? – πάντα ῥεῖ Apr 13 '14 at 20:13
  • Create a test for each c++ feature you're interested in as a separate test. If the compilation fails, you know that the compiler does not support the feature, and if it compiles you know that it supports the feature. This way you don't have to parse error messages and don't really need any sophisticated software. – sdkljhdf hda Apr 14 '14 at 21:10
  • @lego The question doesn't concern C++11 compiler support, it only concerns what C++11 features are actually used in some C++ source code – Erik Sjölund Apr 14 '14 at 21:15

3 Answers3

3

What you are describing is static code analysis. The canonical tool is of course lint, but things have moved on. Wikipedia lists 23 tools for C/C++. http://en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis

Unfortunately none of them list compliance with specific levels of C++ as a feature. However many of them are rule based and make it easy to add your own rules. The examples you gave are well within the capabilities of many of these tools.

I'm not going to recommend one, partly because I don't know enough, partly because that would be just an opinion. If you are lucky someone has already created a set of rules to do what you want.

david.pfx
  • 10,520
  • 3
  • 30
  • 63
3

As said before, this is static analysis of source code. With some simple grep, you can be able to identify some C++11 features such as C++11 STL containers, noexcept, use of move semantic, auto ...

For a more subtle analysis, I would recommend the use of clang API to parse the code source. You can easily check whether a function (and know which one!) is deleted, constexpr... With that, you can do what ever you want (create a report, write the CMake file...)

In all case, I don't think there is a all-in-one tool and you will have to write some parts yourself.

Ben Hocking
  • 7,790
  • 5
  • 37
  • 52
Davidbrcz
  • 2,335
  • 18
  • 27
2

Try using Clang with -std=c++11 -Wc++98-compat and parsing the error output. (Clang also has some way to generate more machine-friendly diagnostics.) This should be pretty complete, though probably not 100%, and it definitely won't find C++11-only library features you use.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157