Skip to content

Commit 6693df2

Browse files
Merge pull request #101 from anderslanglands/main
Force generation of copy constructors
2 parents cf65062 + c7a2e39 commit 6693df2

File tree

133 files changed

+1736
-83
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

133 files changed

+1736
-83
lines changed

CMakeLists.txt

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ project(cppmm)
44
include(GNUInstallDirs)
55

66
set(CPPMM_MAJOR_VERSION 0)
7-
set(CPPMM_MINOR_VERSION 9)
7+
set(CPPMM_MINOR_VERSION 10)
88
set(CPPMM_PATCH_VERSION 0)
99
set(CPPMM_VERSION "${CPPMM_MAJOR_VERSION}.${CPPMM_MINOR_VERSION}.${CPPMM_PATCH_VERSION}")
1010

@@ -58,3 +58,5 @@ add_subdirectory(test/uniqueptr)
5858
add_subdirectory(test/property)
5959
add_subdirectory(test/opaquebytes)
6060
add_subdirectory(test/deriveattr)
61+
add_subdirectory(test/mimpl)
62+
add_subdirectory(test/copymoveaccess)

astgen/src/ast.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ void NodeFunction::write_json_attrs(json& o) const {
256256
o["in_binding"] = in_binding;
257257
o["in_library"] = in_library;
258258
o["noexcept"] = is_noexcept;
259+
o["definition"] = definition;
259260
}
260261

261262
void NodeFunction::write_parameters_json(json& o) const {

astgen/src/ast.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,8 @@ struct NodeFunction : public NodeAttributeHolder {
308308
std::vector<QType> template_args;
309309
/// The set of exceptions this function might throw
310310
std::vector<Exception> exceptions;
311+
// Function definition
312+
std::string definition;
311313

312314
uint64_t _function_id;
313315

astgen/src/astgen.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ int main(int argc_, const char** argv_) {
207207
#define CPPMM_TRIVIALLY_MOVABLE __attribute__((annotate("cppmm|trivially_movable")))
208208
#define CPPMM_PROPERTIES(x) __attribute__((annotate("cppmm|properties|" #x)))
209209
#define CPPMM_MANUAL __attribute__((annotate("cppmm|manual")))
210+
#define CPPMM_IMPL __attribute__((annotate("cppmm|impl")))
211+
#define CPPMM_COPY_CTOR __attribute__((annotate("cppmm|copy_constructor")))
212+
#define CPPMM_MOVE_CTOR __attribute__((annotate("cppmm|move_constructor")))
210213
211214
#define CPPMM_THROWS(EX, VAR) __attribute__((annotate("cppmm|throws|" #EX "|" #VAR)))
212215
#define CPPMM_NOEXCEPT __attribute__((annotate("cppmm|noexcept")))

astgen/src/process_binding.cpp

+178-30
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "pystring.h"
33
#include "clang/AST/ASTContext.h"
44
#include "clang/AST/Decl.h"
5+
#include "clang/AST/PrettyPrinter.h"
56
#include "clang/AST/DeclCXX.h"
67
#include "clang/AST/DeclTemplate.h"
78
#include "clang/AST/GlobalDecl.h"
@@ -10,6 +11,7 @@
1011
#include "clang/ASTMatchers/ASTMatchers.h"
1112
#include "clang/Basic/LLVM.h"
1213
#include "llvm/Support/Casting.h"
14+
#include "llvm/Support/raw_ostream.h"
1315
#include <cassert>
1416
#include <cstdint>
1517
#include <memory>
@@ -28,6 +30,7 @@ namespace fs = ghc::filesystem;
2830

2931
#include "ast.hpp"
3032
#include "ast_utils.hpp"
33+
#include "base64.hpp"
3134

3235
using namespace clang;
3336
using namespace clang::ast_matchers;
@@ -131,7 +134,7 @@ QType process_qtype(const QualType& qt) {
131134
NodeId id;
132135
if (it == NODE_MAP.end()) {
133136
const ConstantArrayType* cat =
134-
dyn_cast<ConstantArrayType>(qt.getTypePtr());
137+
dyn_cast<ConstantArrayType>(qt.getCanonicalType().getTypePtr());
135138
QType element_type = process_qtype(cat->getElementType());
136139
id = NODES.size();
137140
auto node_type = std::make_unique<NodeConstantArrayType>(
@@ -157,13 +160,12 @@ QType process_qtype(const QualType& qt) {
157160
const std::string pointer_type_name =
158161
qt.getCanonicalType().getAsString();
159162
const std::string pointer_type_node_name = "TYPE:" + pointer_type_name;
160-
163+
161164
auto it = NODE_MAP.find(pointer_type_name);
162165
NodeId id;
163166
if (it == NODE_MAP.end()) {
164167
// need to create the pointer type, create the pointee type first
165-
QType pointee_qtype =
166-
process_qtype(qt->getPointeeType());
168+
QType pointee_qtype = process_qtype(qt->getPointeeType());
167169

168170
// now create the pointer type
169171
id = NODES.size();
@@ -203,7 +205,7 @@ QType process_qtype(const QualType& qt) {
203205
type_node_name = "TYPE:" + mangled_name;
204206
}
205207

206-
// FIXME: hack to work around unsigned long being different sizes on
208+
// FIXME: hack to work around unsigned long being different sizes on
207209
// windows and *nix
208210
if (qt->isBuiltinType() && type_name == "unsigned long") {
209211
const auto* tdt = qt->getAs<TypedefType>();
@@ -213,13 +215,15 @@ QType process_qtype(const QualType& qt) {
213215
} else if (tdt && tdt->getDecl()->getNameAsString() == "size_t") {
214216
type_name = "size_t";
215217
type_node_name = "TYPE:size_t";
216-
} else if (tdt && tdt->getDecl()->getNameAsString() == "size_type") {
218+
} else if (tdt &&
219+
tdt->getDecl()->getNameAsString() == "size_type") {
217220
// FIXME: Nasty hack here to get e.g. std::string::size_type
218221
// will this bite us?
219222
type_name = "size_t";
220223
type_node_name = "TYPE:size_t";
221224
} else if (tdt) {
222-
/* SPDLOG_WARN("Unhandled unsigned long typedef {}", tdt->getDecl()->getNameAsString()); */
225+
/* SPDLOG_WARN("Unhandled unsigned long typedef {}",
226+
* tdt->getDecl()->getNameAsString()); */
223227
// If we're some other typedef of unsigned long, try desugaring
224228
// recursively until we get to a typedef we can handle
225229
QualType ds_type = tdt->desugar();
@@ -230,7 +234,8 @@ QType process_qtype(const QualType& qt) {
230234
if (tdt && tdt->getDecl()->getNameAsString() == "int64_t") {
231235
type_name = "int64_t";
232236
type_node_name = "TYPE:int64_t";
233-
} else if (tdt && tdt->getDecl()->getNameAsString() == "ptrdiff_t") {
237+
} else if (tdt &&
238+
tdt->getDecl()->getNameAsString() == "ptrdiff_t") {
234239
type_name = "ptrdiff_t";
235240
type_node_name = "TYPE:ptrdiff_t";
236241
}
@@ -450,11 +455,20 @@ bool has_noexcept_attr(const std::vector<std::string>& attrs) {
450455
attrs.end();
451456
}
452457

453-
bool has_manual_attr(const std::vector<std::string>& attrs) {
454-
return std::find(attrs.begin(), attrs.end(), "cppmm|manual") !=
458+
bool has_copy_ctor_attr(const std::vector<std::string>& attrs) {
459+
return std::find(attrs.begin(), attrs.end(), "cppmm|copy_constructor") !=
460+
attrs.end();
461+
}
462+
463+
bool has_move_ctor_attr(const std::vector<std::string>& attrs) {
464+
return std::find(attrs.begin(), attrs.end(), "cppmm|move_constructor") !=
455465
attrs.end();
456466
}
457467

468+
bool has_manual_attr(const std::vector<std::string>& attrs) {
469+
return std::find(attrs.begin(), attrs.end(), "cppmm|manual") != attrs.end();
470+
}
471+
458472
/// Create a new node for the given method decl and return it
459473
NodePtr process_method_decl(const CXXMethodDecl* cmd,
460474
std::vector<std::string> attrs,
@@ -1003,6 +1017,10 @@ bool has_opaquebytes_attr(const std::vector<std::string>& attrs) {
10031017
attrs.end();
10041018
}
10051019

1020+
bool has_impl_attr(const std::vector<std::string>& attrs) {
1021+
return std::find(attrs.begin(), attrs.end(), "cppmm|impl") != attrs.end();
1022+
}
1023+
10061024
bool is_public_copy_ctor(const Decl* cmd) {
10071025
if (const CXXConstructorDecl* cd = dyn_cast<CXXConstructorDecl>(cmd)) {
10081026
SPDLOG_DEBUG("ctor {}", cd->getQualifiedNameAsString());
@@ -1016,6 +1034,24 @@ bool is_public_copy_ctor(const Decl* cmd) {
10161034
}
10171035
}
10181036

1037+
bool is_inaccessible_copy_ctor(const Decl* cmd) {
1038+
if (const CXXConstructorDecl* cd = dyn_cast<CXXConstructorDecl>(cmd)) {
1039+
return cd->isCopyConstructor() && (cd->getAccess() != AS_public ||
1040+
cd->isDeleted());
1041+
} else {
1042+
return false;
1043+
}
1044+
}
1045+
1046+
bool is_inaccessible_move_ctor(const Decl* cmd) {
1047+
if (const CXXConstructorDecl* cd = dyn_cast<CXXConstructorDecl>(cmd)) {
1048+
return cd->isMoveConstructor() && (cd->getAccess() != AS_public ||
1049+
cd->isDeleted());
1050+
} else {
1051+
return false;
1052+
}
1053+
}
1054+
10191055
bool is_public_move_ctor(const Decl* cmd) {
10201056
if (const CXXConstructorDecl* cd = dyn_cast<CXXConstructorDecl>(cmd)) {
10211057
SPDLOG_DEBUG("ctor {}", cd->getQualifiedNameAsString());
@@ -1029,13 +1065,63 @@ bool is_public_move_ctor(const Decl* cmd) {
10291065
}
10301066
}
10311067

1068+
bool has_forbidden_copy_ctor(const CXXRecordDecl* crd) {
1069+
for (const Decl* d: crd->decls()) {
1070+
if (is_inaccessible_copy_ctor(d)) {
1071+
return true;
1072+
}
1073+
}
1074+
1075+
1076+
for (const auto base : crd->bases()) {
1077+
if (const CXXRecordDecl* base_crd =
1078+
base.getType()->getAsCXXRecordDecl()) {
1079+
if (has_forbidden_copy_ctor(base_crd)) {
1080+
return true;
1081+
}
1082+
}
1083+
}
1084+
1085+
return false;
1086+
}
1087+
1088+
bool has_forbidden_move_ctor(const CXXRecordDecl* crd) {
1089+
for (const Decl* d: crd->decls()) {
1090+
if (is_inaccessible_move_ctor(d)) {
1091+
return true;
1092+
}
1093+
}
1094+
1095+
1096+
for (const auto base : crd->bases()) {
1097+
if (const CXXRecordDecl* base_crd =
1098+
base.getType()->getAsCXXRecordDecl()) {
1099+
if (has_forbidden_move_ctor(base_crd)) {
1100+
return true;
1101+
}
1102+
}
1103+
}
1104+
1105+
return false;
1106+
}
1107+
10321108
void has_public_copy_move_ctor(const CXXRecordDecl* crd,
10331109
bool& has_public_copy_ctor,
10341110
bool& has_public_move_ctor) {
1035-
for (const Decl* d : crd->decls()) {
1036-
has_public_copy_ctor |= is_public_copy_ctor(d);
1037-
has_public_move_ctor |= is_public_move_ctor(d);
1038-
}
1111+
// for (const Decl* d : crd->decls()) {
1112+
// // has_public_copy_ctor |= is_public_copy_ctor(d);
1113+
// // has_public_move_ctor |= is_public_move_ctor(d);
1114+
// has_public_copy_ctor |= is_inaccessible_copy_ctor(d);
1115+
// has_public_move_ctor |= is_inaccessible_move_ctor(d);
1116+
// }
1117+
// has_public_copy_ctor = !has_public_copy_ctor;
1118+
// has_public_move_ctor = !has_public_move_ctor;
1119+
1120+
// has_public_copy_ctor = crd->hasTrivialCopyConstructor() || crd->hasNonTrivialCopyConstructor();
1121+
has_public_move_ctor = (crd->hasTrivialMoveConstructor() || crd->hasNonTrivialMoveConstructor()) && !has_forbidden_move_ctor(crd);
1122+
1123+
has_public_copy_ctor = !has_forbidden_copy_ctor(crd);
1124+
// has_public_move_ctor = !has_forbidden_move_ctor(crd);
10391125
}
10401126

10411127
std::vector<std::string> get_properties(const std::vector<std::string>& attrs) {
@@ -1192,10 +1278,13 @@ void process_concrete_record(const CXXRecordDecl* crd, std::string filename,
11921278
for (NodePtr& method : binding_methods) {
11931279
NodeMethod* mptr = (NodeMethod*)method.get();
11941280
if (has_manual_attr(mptr->attrs)) {
1195-
mptr->in_binding = true;
1281+
mptr->in_binding = true;
11961282
mptr->is_noexcept |= has_noexcept_attr(mptr->attrs);
11971283
function_map[mptr->_function_id] = mptr;
11981284

1285+
mptr->is_copy_constructor = has_copy_ctor_attr(mptr->attrs);
1286+
mptr->is_move_constructor = has_move_ctor_attr(mptr->attrs);
1287+
11991288
NodeId id = NODES.size();
12001289
NODE_MAP[method->qualified_name] = id;
12011290
NODES.emplace_back(std::move(method));
@@ -1213,16 +1302,16 @@ void process_concrete_record(const CXXRecordDecl* crd, std::string filename,
12131302
record_name, node_tu->qualified_name, *m);
12141303
}
12151304
}
1305+
}
12161306

1217-
for (const auto& n : binding_methods) {
1218-
const auto* m = (NodeMethod*)n.get();
1219-
if (m && m->is_user_provided && !m->in_library &&
1220-
!m->is_deleted && !has_manual_attr(m->attrs)) {
1221-
SPDLOG_WARN("[{}]({}) - \n"
1222-
"{} is declared in the binding but not present "
1223-
"in the library",
1224-
record_name, node_tu->qualified_name, *m);
1225-
}
1307+
for (const auto& n : binding_methods) {
1308+
const auto* m = (NodeMethod*)n.get();
1309+
if (m && m->is_user_provided && !m->in_library && !m->is_deleted &&
1310+
!has_manual_attr(m->attrs)) {
1311+
SPDLOG_WARN("[{}]({}) - \n"
1312+
"{} is declared in the binding but not present "
1313+
"in the library",
1314+
record_name, node_tu->qualified_name, *m);
12261315
}
12271316
}
12281317

@@ -1285,7 +1374,14 @@ void process_concrete_record(const CXXRecordDecl* crd, std::string filename,
12851374
void handle_cxx_record_decl(const CXXRecordDecl* crd) {
12861375
ASTContext& ctx = crd->getASTContext();
12871376
SourceManager& sm = ctx.getSourceManager();
1288-
const auto& loc = crd->getLocation();
1377+
auto loc = crd->getLocation();
1378+
1379+
// we don't care about locations in macros, we always want their expansions
1380+
// if we're using macros to generate functions
1381+
if (loc.isMacroID()) {
1382+
auto range = sm.getExpansionRange(loc);
1383+
loc = range.getBegin();
1384+
}
12891385

12901386
const auto mng_ctx = ctx.createMangleContext();
12911387

@@ -1415,7 +1511,13 @@ void handle_binding_function(const FunctionDecl* fd) {
14151511

14161512
ASTContext& ctx = fd->getASTContext();
14171513
SourceManager& sm = ctx.getSourceManager();
1418-
const auto& loc = fd->getLocation();
1514+
auto loc = fd->getLocation();
1515+
// we don't care about locations in macros, we always want their expansions
1516+
// if we're using macros to generate functions
1517+
if (loc.isMacroID()) {
1518+
auto range = sm.getExpansionRange(loc);
1519+
loc = range.getBegin();
1520+
}
14191521
std::string filename = sm.getFilename(loc).str();
14201522

14211523
// Get the translation unit node we're going to add this Function to
@@ -1428,6 +1530,29 @@ void handle_binding_function(const FunctionDecl* fd) {
14281530
process_function_parameters(fd, return_qtype, params);
14291531
auto exceptions = get_exceptions(attrs);
14301532

1533+
// If we've marked the function as being an implementation with CPPMM_IMPL,
1534+
// and it has a valid function body, grab the entire function definition,
1535+
// base64-encode it and bung it into NodeFunction, then add the node to the
1536+
// translation unit. It will then be picked up in asttoc, and the function
1537+
// body spat out as an inline function that asttoc will wrap.
1538+
std::string body;
1539+
if (has_impl_attr(attrs)) {
1540+
if (fd->isThisDeclarationADefinition()) {
1541+
std::string s;
1542+
llvm::raw_string_ostream sos(s);
1543+
fd->print(sos);
1544+
1545+
auto function_spelling = s;
1546+
auto remove_macro = ps::replace(function_spelling, "__attribute__((annotate(\"cppmm|impl\")))", "");
1547+
auto rename_function = ps::replace(remove_macro, function_short_name + "(", function_short_name + "_impl(");
1548+
body = base64::base64_encode(rename_function);
1549+
1550+
} else {
1551+
SPDLOG_ERROR("Function {} marked as impl but could not get body",
1552+
fd->getQualifiedNameAsString());
1553+
}
1554+
}
1555+
14311556
const std::vector<NodeId> namespaces =
14321557
get_namespaces(fd->getParent(), node_tu);
14331558

@@ -1437,12 +1562,35 @@ void handle_binding_function(const FunctionDecl* fd) {
14371562
function_short_name, return_qtype, std::move(params),
14381563
std::move(namespaces), get_comment_base64(fd), std::move(exceptions));
14391564

1440-
SPDLOG_DEBUG("Adding binding function {}", node_function);
1565+
node_function.definition = body;
14411566

1442-
if (it != binding_functions.end()) {
1443-
it->second.emplace_back(std::move(node_function));
1567+
if (body.empty()) {
1568+
if (it != binding_functions.end()) {
1569+
it->second.emplace_back(std::move(node_function));
1570+
} else {
1571+
binding_functions[function_qual_name] = {node_function};
1572+
}
14441573
} else {
1445-
binding_functions[function_qual_name] = {node_function};
1574+
// Rename our function to _impl and give the original name to the C
1575+
// function as an alias
1576+
node_function.attrs.push_back("cppmm|rename|" + node_function.short_name);
1577+
node_function.short_name = node_function.short_name + "_impl";
1578+
node_function.qualified_name = node_function.qualified_name + "_impl";
1579+
1580+
auto fnptr =
1581+
std::make_unique<NodeFunction>(std::move(node_function));
1582+
NodeId id = NODES.size();
1583+
fnptr->id = id;
1584+
// add the function to its TU
1585+
auto* node_tu =
1586+
(NodeTranslationUnit*)NODES.at(node_function.context).get();
1587+
// process the namespaces again to make sure we've got the
1588+
// namespaces in the TU
1589+
const std::vector<NodeId> namespaces =
1590+
get_namespaces(fd->getParent(), node_tu);
1591+
fnptr->context = node_tu->id;
1592+
node_tu->children.push_back(id);
1593+
NODES.emplace_back(std::move(fnptr));
14461594
}
14471595
}
14481596

0 commit comments

Comments
 (0)