Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add better C support #135

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
87 changes: 86 additions & 1 deletion include/cppast/compile_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -26,8 +26,14 @@ enum class cpp_standard
cpp_17,
cpp_2a,
cpp_20,
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,
Expand All @@ -52,12 +58,82 @@ inline const char* to_string(cpp_standard standard) noexcept
return "c++2a";
case cpp_standard::cpp_20:
return "c++20";
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 The C/C++ standard corresponding to the string, e.g. `cpp_14` for `c++14`
/// \throws std::invalid_argument for an unknown language standard
inline cpp_standard to_standard(const std::string& str)
{
if (str == "c++98")
return cpp_standard::cpp_98;
else if (str == "c++03")
return cpp_standard::cpp_03;
else if (str == "c++11")
return cpp_standard::cpp_11;
else if (str == "c++14")
return cpp_standard::cpp_14;
else if (str == "c++1z")
return cpp_standard::cpp_1z;
else if (str == "c++17")
return cpp_standard::cpp_17;
else if (str == "c++2a")
return cpp_standard::cpp_2a;
else if (str == "c++20")
return cpp_standard::cpp_20;
else if (str == "c89")
return cpp_standard::c_89;
else if (str == "c99")
return cpp_standard::c_99;
else if (str == "c11")
return cpp_standard::c_11;
else if (str == "c17")
return cpp_standard::c_17;
else if (str == "c2x")
return cpp_standard::c_2x;
else
throw std::invalid_argument("invalid C/C++ standard '" + str + "'");
}

/// \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:
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
{
Expand Down Expand Up @@ -114,6 +190,12 @@ class compile_config
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)) {}

Expand Down Expand Up @@ -157,6 +239,9 @@ class compile_config
/// \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
Expand Down
19 changes: 16 additions & 3 deletions include/cppast/cpp_storage_class_specifiers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,16 @@ enum cpp_storage_class_specifiers : int

cpp_storage_class_auto = 1, //< *automatic* storage duration.

cpp_storage_class_static = 2, //< *static* or *thread* storage duration and *internal* linkage.
cpp_storage_class_extern = 4, //< *static* or *thread* storage duration and *external* linkage.

cpp_storage_class_thread_local = 8, //< *thread* storage duration.
cpp_storage_class_register = 2, //< *automatic* storage duration.
/// Hints to the compiler to keep this in a register.
/// \notes In C a register variable cannot have its address taken. For C++ `register` is
/// deprecated in C++11 and removed in C++17.

cpp_storage_class_static = 4, //< *static* or *thread* storage duration and *internal* linkage.
cpp_storage_class_extern = 8, //< *static* or *thread* storage duration and *external* linkage.

cpp_storage_class_thread_local = 16, //< *thread* storage duration.
/// \notes This is the only one that can be combined with the others.
};

Expand All @@ -49,6 +55,13 @@ inline bool is_extern(cpp_storage_class_specifiers spec) noexcept
{
return (spec & cpp_storage_class_extern) != 0;
}

/// \returns Whether the [cppast::cpp_storage_class_specifiers]() contain `register`.
inline bool is_register(cpp_storage_class_specifiers spec) noexcept
{
return (spec & cpp_storage_class_register) != 0;
}
} // namespace cppast


#endif // CPPAST_CPP_STORAGE_CLASS_SPECIFIERS_HPP_INCLUDED
48 changes: 38 additions & 10 deletions include/cppast/cpp_type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,25 +286,47 @@ class cpp_dependent_type final : public cpp_type
std::unique_ptr<cpp_type> dependee_;
};

/// The kinds of C++ cv qualifiers.
enum cpp_cv : int
/// Flags for the kinds of C/C++ qualifiers.
enum cpp_cv_flags : int
{
cpp_cv_none,
cpp_cv_const,
cpp_cv_volatile,
cpp_cv_const_volatile,
cpp_cv_const, //< constant type
cpp_cv_volatile, //< volatile type
cpp_cv_restrict, //< restrict pointer type (C-only)
cpp_cv_atomic, //< atomic type (C-only)

_flag_set_size, //< \exclude
};

/// Flag set for the kinds for C/C++ qualifiers.
using cpp_cv = type_safe::flag_set<cpp_cv_flags>;

/// Represents a const volatile qualified type
constexpr cpp_cv cpp_cv_const_volatile = cpp_cv(cpp_cv_const) | cpp_cv_volatile;
/// Represents an unqualified type
constexpr cpp_cv cpp_cv_none = cpp_cv();

/// \returns `true` if the qualifier contains `const`.
inline bool is_const(cpp_cv cv) noexcept
inline bool is_const(const cpp_cv& cv) noexcept
{
return cv == cpp_cv_const || cv == cpp_cv_const_volatile;
return (cv & cpp_cv_const) != 0;
}

/// \returns `true` if the qualifier contains `volatile`.
inline bool is_volatile(cpp_cv cv) noexcept
inline bool is_volatile(const cpp_cv& cv) noexcept
{
return (cv & cpp_cv_volatile) != 0;
}

/// \returns `true` if the qualifier contains `restrict`.
inline bool is_restrict(const cpp_cv& cv) noexcept
{
return cv == cpp_cv_volatile || cv == cpp_cv_const_volatile;
return (cv & cpp_cv_restrict) != 0;
}

/// \returns `true` if the qualifier contains `atomic`.
inline bool is_atomic(const cpp_cv& cv) noexcept
{
return (cv & cpp_cv_atomic) != 0;
}

/// A [cppast::cpp_cv]() qualified [cppast::cpp_type]().
Expand Down Expand Up @@ -355,6 +377,12 @@ const cpp_type& remove_const(const cpp_type& type) noexcept;
/// \returns The type without top-level volatile qualifiers.
const cpp_type& remove_volatile(const cpp_type& type) noexcept;

/// \returns The type without top-level restrict qualifiers.
const cpp_type& remove_restrict(const cpp_type& type) noexcept;

/// \returns The type without top-level atomic qualifiers.
const cpp_type& remove_atomic(const cpp_type& type) noexcept;

/// A pointer to a [cppast::cpp_type]().
class cpp_pointer_type final : public cpp_type
{
Expand Down
2 changes: 1 addition & 1 deletion include/cppast/cppast_fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ enum class visit_filter;

enum cpp_access_specifier_kind : int;
enum cpp_builtin_type_kind : int;
enum cpp_cv : int;
enum cpp_cv_flags : int;
enum cpp_function_body_kind : int;
enum cpp_reference : int;
enum cpp_storage_class_specifiers : int;
Expand Down
3 changes: 3 additions & 0 deletions include/cppast/libclang_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,13 @@ class libclang_compile_config final : public compile_config
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;
};
Expand Down
37 changes: 23 additions & 14 deletions src/code_generator.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (C) 2017-2022 Jonathan Müller and cppast contributors
// SPDX-License-Identifier: MIT

#include "cppast/cpp_type.hpp"
#include <cppast/code_generator.hpp>

#include <cppast/cpp_alias_template.hpp>
Expand Down Expand Up @@ -471,6 +472,8 @@ void write_storage_class(code_generator::output& output, cpp_storage_class_speci
output << keyword("extern") << whitespace;
if (is_thread_local(storage))
output << keyword("thread_local") << whitespace;
if (is_register(storage))
output << keyword("register") << whitespace;
if (is_constexpr)
output << keyword("constexpr") << whitespace;
else if (is_consteval)
Expand Down Expand Up @@ -658,22 +661,28 @@ void write_suffix_virtual(code_generator::output& output, const cpp_virtual& vir
bool write_cv_ref(code_generator::output& output, const cpp_member_function_base& base)
{
auto need_ws = false;
switch (base.cv_qualifier())
auto cv = base.cv_qualifier();

std::vector<const char*> qualifiers;
if (is_const(cv))
qualifiers.push_back("const");
if (is_volatile(cv))
qualifiers.push_back("volatile");
if (is_atomic(cv))
qualifiers.push_back("_Atomic");
if (is_restrict(cv))
qualifiers.push_back("restrict");

bool first = true;
for (auto& q : qualifiers)
{
case cpp_cv_none:
break;
case cpp_cv_const:
output << operator_ws << keyword("const");
need_ws = true;
break;
case cpp_cv_volatile:
output << operator_ws << keyword("volatile");
need_ws = true;
break;
case cpp_cv_const_volatile:
output << operator_ws << keyword("const") << whitespace << keyword("volatile");
if (first)
output << operator_ws;
else
output << whitespace;
output << keyword(std::move(q));
first = false;
need_ws = true;
break;
}

switch (base.ref_qualifier())
Expand Down
4 changes: 4 additions & 0 deletions src/cpp_member_function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ std::string cpp_member_function_base::do_get_signature() const
result += " const";
if (is_volatile(cv_qualifier()))
result += " volatile";
if (is_atomic(cv_qualifier()))
result += " _Atomic";
if (is_restrict(cv_qualifier()))
result += " restrict";

if (ref_qualifier() == cpp_ref_lvalue)
result += " &";
Expand Down
Loading