Merge branch 'foonathan:main' into main

This commit is contained in:
Joey Yakimowich-Payne 2023-01-30 17:21:08 -07:00 committed by GitHub
commit c125883083
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 161 additions and 11 deletions

View file

@ -15,7 +15,7 @@
namespace cppast
{
/// The C++ standard that should be used.
/// The C/C++ standard that should be used.
enum class cpp_standard
{
cpp_98,
@ -26,8 +26,16 @@ enum class cpp_standard
cpp_17,
cpp_2a,
cpp_20,
cpp_2b,
c_89,
c_99,
c_11,
c_17,
c_2x,
cpp_latest = cpp_standard::cpp_14, //< The latest supported C++ standard.
c_latest = cpp_standard::c_17, //< The latest supported C standard.
};
/// \returns A human readable string representing the option,
@ -52,12 +60,52 @@ inline const char* to_string(cpp_standard standard) noexcept
return "c++2a";
case cpp_standard::cpp_20:
return "c++20";
case cpp_standard::cpp_2b:
return "c++2b";
case cpp_standard::c_89:
return "c89";
case cpp_standard::c_99:
return "c99";
case cpp_standard::c_11:
return "c11";
case cpp_standard::c_17:
return "c17";
case cpp_standard::c_2x:
return "c2x";
}
DEBUG_UNREACHABLE(detail::assert_handler{});
return "ups";
}
/// \returns whether the language standard is a C standard
inline bool is_c_standard(cpp_standard standard) noexcept
{
switch (standard)
{
case cpp_standard::cpp_98:
case cpp_standard::cpp_03:
case cpp_standard::cpp_11:
case cpp_standard::cpp_14:
case cpp_standard::cpp_1z:
case cpp_standard::cpp_17:
case cpp_standard::cpp_2a:
case cpp_standard::cpp_20:
case cpp_standard::cpp_2b:
return false;
case cpp_standard::c_89:
case cpp_standard::c_99:
case cpp_standard::c_11:
case cpp_standard::c_17:
case cpp_standard::c_2x:
return true;
}
DEBUG_UNREACHABLE(detail::assert_handler{});
return false;
}
/// Other special compilation flags.
enum class compile_flag
{
@ -114,6 +162,12 @@ public:
return do_get_name();
}
/// \returns Whether to parse files as C rather than C++.
bool use_c() const noexcept
{
return do_use_c();
}
protected:
compile_config(std::vector<std::string> def_flags) : flags_(std::move(def_flags)) {}
@ -157,6 +211,9 @@ private:
/// \notes This allows detecting mismatches of configurations and parsers.
virtual const char* do_get_name() const noexcept = 0;
/// \returns Whether to parse files as C rather than C++.
virtual bool do_use_c() const noexcept = 0;
std::vector<std::string> flags_;
};
} // namespace cppast

View file

@ -187,10 +187,13 @@ private:
return "libclang";
}
bool do_use_c() const noexcept override;
std::string clang_binary_;
bool write_preprocessed_ : 1;
bool fast_preprocessing_ : 1;
bool remove_comments_in_macro_ : 1;
bool use_c_ : 1;
friend detail::libclang_compile_config_access;
};

View file

@ -82,7 +82,7 @@ libclang_compile_config::libclang_compile_config() : libclang_compile_config(CPP
libclang_compile_config::libclang_compile_config(std::string clang_binary)
: compile_config({}), write_preprocessed_(false), fast_preprocessing_(false),
remove_comments_in_macro_(false)
remove_comments_in_macro_(false), use_c_(false)
{
// set given clang binary
set_clang_binary(clang_binary);
@ -226,6 +226,11 @@ cppast::libclang_compile_config::libclang_compile_config(
for (auto i = 0u; i != size; ++i)
{
auto cmd = clang_CompileCommands_getCommand(commands.get(), i);
// If ++ exists within the compiler name (e.g. clang++, g++, etc), use C++
std::string exe(clang_getCString(clang_CompileCommand_getArg(cmd, 0)));
use_c_ = (exe.find("++", 0) == std::string::npos);
auto dir = detail::cxstring(clang_CompileCommand_getDirectory(cmd));
parse_flags(cmd, [&](std::string flag, std::string args) {
if (flag == "-I")
@ -243,11 +248,21 @@ cppast::libclang_compile_config::libclang_compile_config(
add_flag(std::move(flag));
}
else if (flag == "-std")
// standard
{
use_c_ = (args.find("++") == std::string::npos);
add_flag(std::move(flag) + "=" + std::move(args));
}
else if (flag == "-f")
// other options
add_flag(std::move(flag) + std::move(args));
else if (flag == "-x")
{
// language
if (args == "c")
use_c_ = true;
else
use_c_ = false;
}
});
}
}
@ -270,8 +285,9 @@ bool is_valid_binary(const std::string& binary)
void add_default_include_dirs(libclang_compile_config& config)
{
std::string verbose_output;
std::string language = config.use_c() ? "-xc" : "-xc++";
tpl::Process process(
detail::libclang_compile_config_access::clang_binary(config) + " -x c++ -v -", "",
detail::libclang_compile_config_access::clang_binary(config) + " " + language + " -v -", "",
[](const char*, std::size_t) {},
[&](const char* str, std::size_t n) { verbose_output.append(str, n); }, true);
process.write("", 1);
@ -415,6 +431,66 @@ void libclang_compile_config::do_set_flags(cpp_standard standard, compile_flags
}
else
throw std::invalid_argument("c++20 is not yet supported for current version of clang");
case cpp_standard::cpp_2b:
if (libclang_parser::libclang_minor_version() >= 61)
{ // Corresponds to Clang version 12
if (flags & compile_flag::gnu_extensions)
add_flag("-std=gnu++2a");
else
add_flag("-std=c++2a");
break;
}
else
throw std::invalid_argument("c++2b is not yet supported for current version of clang");
case cpp_standard::c_89:
if (flags & compile_flag::gnu_extensions)
add_flag("-std=gnu89");
else
add_flag("-std=c89");
break;
case cpp_standard::c_99:
if (flags & compile_flag::gnu_extensions)
add_flag("-std=gnu99");
else
add_flag("-std=c99");
break;
case cpp_standard::c_11:
if (flags & compile_flag::gnu_extensions)
add_flag("-std=gnu11");
else
add_flag("-std=c11");
break;
case cpp_standard::c_17:
if (libclang_parser::libclang_minor_version() >= 45)
{ // Corresponds to Clang version 6
if (flags & compile_flag::gnu_extensions)
add_flag("-std=gnu17");
else
add_flag("-std=c17");
break;
}
else
throw std::invalid_argument("c17 is not yet supported for current version of clang");
case cpp_standard::c_2x:
if (libclang_parser::libclang_minor_version() >= 59)
{ // Corresponds to Clang version 9
if (flags & compile_flag::gnu_extensions)
add_flag("-std=gnu2x");
else
add_flag("-std=c2x");
break;
}
else
throw std::invalid_argument("c2x is not yet supported for current version of clang");
}
// Add language flag for C or C++
if (is_c_standard(standard)) {
add_flag("-xc");
use_c_ = true;
} else {
add_flag("-xc++");
use_c_ = false;
}
if (flags & compile_flag::ms_compatibility)
@ -452,6 +528,11 @@ void libclang_compile_config::do_remove_macro_definition(std::string name)
add_flag("-U" + std::move(name));
}
bool libclang_compile_config::do_use_c() const noexcept
{
return use_c_;
}
type_safe::optional<libclang_compile_config> cppast::find_config_for(
const libclang_compilation_database& database, std::string file_name)
{
@ -465,7 +546,7 @@ type_safe::optional<libclang_compile_config> cppast::find_config_for(
if (database.has_config(file_name))
return libclang_compile_config(database, std::move(file_name));
static const char* extensions[]
= {".h", ".hpp", ".cpp", ".h++", ".c++", ".hxx", ".cxx", ".hh", ".cc", ".H", ".C"};
= {".h", ".hpp", ".cpp", ".h++", ".c++", ".hxx", ".cxx", ".hh", ".cc", ".H", ".C", ".c"};
for (auto ext : extensions)
{
auto name = file_name + ext;
@ -502,8 +583,8 @@ namespace
std::vector<const char*> get_arguments(const libclang_compile_config& config)
{
std::vector<const char*> args
// TODO: Why? and Why?
= {"-x", "c++", "-I."}; // force C++ and enable current directory for include search
// TODO: Why?
= {"-I."}; // enable current directory for include search
for (auto& flag : detail::libclang_compile_config_access::flags(config))
args.push_back(flag.c_str());
return args;

View file

@ -174,11 +174,12 @@ std::string diagnostics_flags()
// get the command that returns all macros defined in the TU
std::string get_macro_command(const libclang_compile_config& c, const char* full_path)
{
// -x c++: force C++ as input language
// -xc/-xc++: force C or C++ as input language
// -I.: add current working directory to include search path
// -E: print preprocessor output
// -dM: print macro definitions instead of preprocessed file
auto flags = std::string("-x c++ -I. -E -dM");
std::string language = c.use_c() ? "-xc" : "-xc++";
auto flags = language + " -I. -E -dM";
flags += diagnostics_flags();
std::string cmd(detail::libclang_compile_config_access::clang_binary(c) + " " + std::move(flags)
@ -198,10 +199,11 @@ std::string get_macro_command(const libclang_compile_config& c, const char* full
std::string get_preprocess_command(const libclang_compile_config& c, const char* full_path,
const char* macro_file_path)
{
// -x c++: force C++ as input language
// -xc/-xc++: force C or C++ as input language
// -E: print preprocessor output
// -dD: keep macros
auto flags = std::string("-x c++ -E -dD");
std::string language = c.use_c() ? "-xc" : "-xc++";
auto flags = language + " -E -dD";
// -CC: keep comments, even in macro
// -C: keep comments, but not in macro

View file

@ -27,6 +27,11 @@ TEST_CASE("parse_files")
{
return "null";
}
bool do_use_c() const noexcept override
{
return false;
}
} config;
class null_parser : public parser

View file

@ -310,6 +310,8 @@ try
config.set_flags(cppast::cpp_standard::cpp_2a, flags);
else if (options["std"].as<std::string>() == "c++20")
config.set_flags(cppast::cpp_standard::cpp_20, flags);
else if (options["std"].as<std::string>() == "c++2b")
config.set_flags(cppast::cpp_standard::cpp_2b, flags);
else
{
print_error("invalid value '" + options["std"].as<std::string>() + "' for std flag");