Skip to content
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
17 changes: 13 additions & 4 deletions include/cppast/cpp_type_alias.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,35 @@ class cpp_type_alias final : public cpp_entity

/// \returns A newly created and registered type alias.
static std::unique_ptr<cpp_type_alias> build(const cpp_entity_index& idx, cpp_entity_id id,
std::string name, std::unique_ptr<cpp_type> type);
std::string name, std::unique_ptr<cpp_type> type,
bool use_c_style = false);

/// \returns A newly created type alias that isn't registered.
/// \notes This function is intendend for templated type aliases.
static std::unique_ptr<cpp_type_alias> build(std::string name, std::unique_ptr<cpp_type> type);
static std::unique_ptr<cpp_type_alias> build(std::string name, std::unique_ptr<cpp_type> type,
bool use_c_style = false);

/// \returns A reference to the aliased [cppast::cpp_type]().
const cpp_type& underlying_type() const noexcept
{
return *type_;
}

/// \returns Whether to generate C-style typedefs instead of C++ using statements
bool use_c_style() const noexcept
{
return use_c_style_;
}

private:
cpp_type_alias(std::string name, std::unique_ptr<cpp_type> type)
: cpp_entity(std::move(name)), type_(std::move(type))
cpp_type_alias(std::string name, std::unique_ptr<cpp_type> type, bool use_c_style)
: cpp_entity(std::move(name)), type_(std::move(type)), use_c_style_(use_c_style)
{}

cpp_entity_kind do_get_entity_kind() const noexcept override;

std::unique_ptr<cpp_type> type_;
bool use_c_style_;
};
} // namespace cppast

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
60 changes: 40 additions & 20 deletions src/code_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,25 @@ bool generate_type_alias(code_generator& generator, const cpp_type_alias& alias,
code_generator::output output(type_safe::ref(generator), type_safe::ref(alias), cur_access);
if (output)
{
output << keyword("using") << whitespace << identifier(alias.name()) << operator_ws
<< punctuation("=") << operator_ws;
if (output.options() & code_generator::exclude_target)
output.excluded(alias);
if (alias.use_c_style())
{
output << keyword("typedef") << whitespace;
if (output.options() & code_generator::exclude_target)
output.excluded(alias);
else
detail::write_type(output, alias.underlying_type(), alias.name());
output << punctuation(";") << newl;
}
else
detail::write_type(output, alias.underlying_type(), "");
output << punctuation(";") << newl;
{
output << keyword("using") << whitespace << identifier(alias.name()) << operator_ws
<< punctuation("=") << operator_ws;
if (output.options() & code_generator::exclude_target)
output.excluded(alias);
else
detail::write_type(output, alias.underlying_type(), "");
output << punctuation(";") << newl;
}
}
return static_cast<bool>(output);
}
Expand Down Expand Up @@ -471,6 +483,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 +672,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