Skip to content

Commit ce218df

Browse files
MinhLu12foonathan
authored andcommitted
Add basic C++20 support
1 parent 019163b commit ce218df

File tree

4 files changed

+73
-25
lines changed

4 files changed

+73
-25
lines changed

include/cppast/compile_config.hpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ enum class cpp_standard
2222
cpp_03,
2323
cpp_11,
2424
cpp_14,
25-
26-
cpp_1z, //< Upcoming C++17 (experimental).
25+
cpp_1z,
26+
cpp_17,
27+
cpp_2a,
28+
cpp_20,
2729

2830
cpp_latest = cpp_standard::cpp_14, //< The latest supported C++ standard.
2931
};
@@ -44,6 +46,12 @@ inline const char* to_string(cpp_standard standard) noexcept
4446
return "c++14";
4547
case cpp_standard::cpp_1z:
4648
return "c++1z";
49+
case cpp_standard::cpp_17:
50+
return "c++17";
51+
case cpp_standard::cpp_2a:
52+
return "c++2a";
53+
case cpp_standard::cpp_20:
54+
return "c++20";
4755
}
4856

4957
DEBUG_UNREACHABLE(detail::assert_handler{});

src/libclang/libclang_parser.cpp

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -248,8 +248,8 @@ namespace
248248
{
249249
bool is_valid_binary(const std::string& binary)
250250
{
251-
tpl::Process process(binary + " -v", "", [](const char*, std::size_t) {},
252-
[](const char*, std::size_t) {});
251+
tpl::Process process(
252+
binary + " -v", "", [](const char*, std::size_t) {}, [](const char*, std::size_t) {});
253253
return process.get_exit_status() == 0;
254254
}
255255

@@ -262,11 +262,10 @@ bool is_valid_binary(const std::string& binary)
262262
void add_default_include_dirs(libclang_compile_config& config)
263263
{
264264
std::string verbose_output;
265-
tpl::Process process(detail::libclang_compile_config_access::clang_binary(config)
266-
+ " -x c++ -v -",
267-
"", [](const char*, std::size_t) {},
268-
[&](const char* str, std::size_t n) { verbose_output.append(str, n); },
269-
true);
265+
tpl::Process process(
266+
detail::libclang_compile_config_access::clang_binary(config) + " -x c++ -v -", "",
267+
[](const char*, std::size_t) {},
268+
[&](const char* str, std::size_t n) { verbose_output.append(str, n); }, true);
270269
process.write("", 1);
271270
process.close_stdin();
272271
process.get_exit_status();
@@ -326,7 +325,9 @@ bool libclang_compile_config::set_clang_binary(std::string binary)
326325
// first search in current directory, then in PATH
327326
static const char* paths[]
328327
= {"./clang++", "clang++", "./clang++-4.0", "clang++-4.0", "./clang++-5.0",
329-
"clang++-5.0", "./clang++-6.0", "clang++-6.0", "./clang-7", "clang-7"};
328+
"clang++-5.0", "./clang++-6.0", "clang++-6.0", "./clang-7", "clang-7",
329+
"./clang-8", "clang-8", "./clang-9", "clang-9", "./clang-10",
330+
"clang-10", "./clang-11", "clang-11"};
330331
for (auto& p : paths)
331332
if (is_valid_binary(p))
332333
{
@@ -373,6 +374,39 @@ void libclang_compile_config::do_set_flags(cpp_standard standard, compile_flags
373374
else
374375
add_flag("-std=c++1z");
375376
break;
377+
case cpp_standard::cpp_17:
378+
if (libclang_parser::libclang_minor_version() >= 43)
379+
{ // Corresponds to Clang version 5
380+
if (flags & compile_flag::gnu_extensions)
381+
add_flag("-std=gnu++17");
382+
else
383+
add_flag("-std=c++17");
384+
break;
385+
}
386+
else
387+
throw std::invalid_argument("c++17 is not yet supported for current version of clang");
388+
case cpp_standard::cpp_2a:
389+
if (libclang_parser::libclang_minor_version() >= 59)
390+
{ // Corresponds to Clang version 9
391+
if (flags & compile_flag::gnu_extensions)
392+
add_flag("-std=gnu++2a");
393+
else
394+
add_flag("-std=c++2a");
395+
break;
396+
}
397+
else
398+
throw std::invalid_argument("c++2a is not yet supported for current version of clang");
399+
case cpp_standard::cpp_20:
400+
if (libclang_parser::libclang_minor_version() >= 60)
401+
{ // Corresponds to Clang version 10
402+
if (flags & compile_flag::gnu_extensions)
403+
add_flag("-std=gnu++20");
404+
else
405+
add_flag("-std=c++20");
406+
break;
407+
}
408+
else
409+
throw std::invalid_argument("c++20 is not yet supported for current version of clang");
376410
}
377411

378412
if (flags & compile_flag::ms_compatibility)
@@ -559,7 +593,8 @@ unsigned get_line_no(const CXCursor& cursor)
559593
}
560594
} // namespace
561595
std::unique_ptr<cpp_file> libclang_parser::do_parse(const cpp_entity_index& idx, std::string path,
562-
const compile_config& c) const try
596+
const compile_config& c) const
597+
try
563598
{
564599
DEBUG_ASSERT(std::strcmp(c.name(), "libclang") == 0, detail::precondition_error_handler{},
565600
"config has mismatched type");

test/test_parser.hpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,18 @@ inline void write_file(const char* name, const char* code)
2323
file << code;
2424
}
2525

26-
inline cppast::libclang_compile_config make_test_config()
27-
{
28-
using namespace cppast;
29-
30-
libclang_compile_config config;
31-
config.set_flags(cpp_standard::cpp_latest);
32-
return config;
33-
}
34-
3526
inline std::unique_ptr<cppast::cpp_file> parse_file(const cppast::cpp_entity_index& idx,
3627
const char* name,
37-
bool fast_preprocessing = false)
28+
bool fast_preprocessing = false,
29+
cppast::cpp_standard standard
30+
= cppast::cpp_standard::cpp_latest)
3831
{
3932
using namespace cppast;
40-
static auto config = make_test_config();
33+
34+
// Creating a config is expensive, so we remember a default one.
35+
static auto default_config = libclang_compile_config();
36+
auto config = default_config;
37+
config.set_flags(standard);
4138
config.fast_preprocessing(fast_preprocessing);
4239

4340
libclang_parser p(default_logger());
@@ -50,10 +47,12 @@ inline std::unique_ptr<cppast::cpp_file> parse_file(const cppast::cpp_entity_ind
5047

5148
inline std::unique_ptr<cppast::cpp_file> parse(const cppast::cpp_entity_index& idx,
5249
const char* name, const char* code,
53-
bool fast_preprocessing = false)
50+
bool fast_preprocessing = false,
51+
cppast::cpp_standard standard
52+
= cppast::cpp_standard::cpp_latest)
5453
{
5554
write_file(name, code);
56-
return parse_file(idx, name, fast_preprocessing);
55+
return parse_file(idx, name, fast_preprocessing, standard);
5756
}
5857

5958
class test_generator : public cppast::code_generator

tool/main.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ int main(int argc, char* argv[]) try
203203
cxxopts::value<std::string>())
204204
("database_file", "set the file name whose configuration will be used regardless of the current file name",
205205
cxxopts::value<std::string>())
206-
("std", "set the C++ standard (c++98, c++03, c++11, c++14, c++1z (experimental))",
206+
("std", "set the C++ standard (c++98, c++03, c++11, c++14, c++1z (experimental), c++17, c++2a, c++20)",
207207
cxxopts::value<std::string>()->default_value(cppast::to_string(cppast::cpp_standard::cpp_latest)))
208208
("I,include_directory", "add directory to include search path",
209209
cxxopts::value<std::vector<std::string>>())
@@ -304,6 +304,12 @@ int main(int argc, char* argv[]) try
304304
config.set_flags(cppast::cpp_standard::cpp_14, flags);
305305
else if (options["std"].as<std::string>() == "c++1z")
306306
config.set_flags(cppast::cpp_standard::cpp_1z, flags);
307+
else if (options["std"].as<std::string>() == "c++17")
308+
config.set_flags(cppast::cpp_standard::cpp_17, flags);
309+
else if (options["std"].as<std::string>() == "c++2a")
310+
config.set_flags(cppast::cpp_standard::cpp_2a, flags);
311+
else if (options["std"].as<std::string>() == "c++20")
312+
config.set_flags(cppast::cpp_standard::cpp_20, flags);
307313
else
308314
{
309315
print_error("invalid value '" + options["std"].as<std::string>() + "' for std flag");

0 commit comments

Comments
 (0)