Skip to content

Commit 1b1e896

Browse files
authored
Force each typedef to have a translation rule (#552)
Also abort if there is no rule for a typedef, don't walk the typedef chain. This forces adding a new rules where needed and forces using the typedef instead of the canonical type. Closes #535, depends on #551
1 parent cab6a2b commit 1b1e896

92 files changed

Lines changed: 922 additions & 276 deletions

Some content is hidden

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

‎cpp2rust/converter/converter.cpp‎

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -770,13 +770,13 @@ bool Converter::IsPassThroughRule(clang::Expr *expr) const {
770770
rule->body[0]);
771771
}
772772

773-
bool Converter::RecordDerivesCopy(const clang::RecordDecl *decl) {
773+
bool Converter::RecordDerivesCopy(clang::QualType type) {
774+
auto decl = type->getAsRecordDecl();
774775
if (auto cxx = llvm::dyn_cast<clang::CXXRecordDecl>(decl);
775776
cxx && cxx->isLambda()) {
776777
return false;
777778
}
778-
if (auto rule =
779-
RuleRegistry::Search(ctx_, ctx_.getCanonicalTagType(decl)).first) {
779+
if (auto rule = RuleRegistry::Search(ctx_, type).first) {
780780
auto &derives = rule->type_info.derives;
781781
return std::find(derives.begin(), derives.end(), "Copy") != derives.end();
782782
}
@@ -804,9 +804,9 @@ bool Converter::RecordHasCopyableFields(const clang::RecordDecl *decl) {
804804
}
805805

806806
// Look recursively into fields that are RecordDecl, or arrays of them
807-
if (auto field_record =
808-
ctx_.getBaseElementType(f->getType())->getAsRecordDecl()) {
809-
if (!RecordDerivesCopy(field_record)) {
807+
if (auto field_type = ctx_.getBaseElementType(f->getType());
808+
field_type->getAsRecordDecl()) {
809+
if (!RecordDerivesCopy(field_type)) {
810810
return false;
811811
}
812812
}
@@ -2304,11 +2304,6 @@ std::string Converter::getIntegerLiteral(clang::IntegerLiteral *expr,
23042304
auto type_as_string = GetUnsafeTypeAsString(ty);
23052305

23062306
if (ty->isFloatingType() || incl_type) {
2307-
if (value.isZero()) {
2308-
if (auto init = Mapper::MapInitializer(*this, ty); !init.empty()) {
2309-
return init;
2310-
}
2311-
}
23122307
return getTypedLiteral(num_as_string.c_str(), type_as_string);
23132308
}
23142309

@@ -4227,8 +4222,8 @@ std::string Converter::GetArrayDefaultAsString(clang::QualType qual_type) {
42274222
auto size_as_string = GetNumAsString(array_type->getSize());
42284223
auto element_type = array_type->getElementType();
42294224
auto element_type_as_string = GetDefaultAsString(element_type);
4230-
if (auto *rec = element_type->getAsRecordDecl()) {
4231-
if (!RecordDerivesCopy(rec)) {
4225+
if (element_type->getAsRecordDecl()) {
4226+
if (!RecordDerivesCopy(element_type)) {
42324227
return std::format("std::array::from_fn::<_, {}, _>(|_| {})",
42334228
size_as_string.c_str(), element_type_as_string);
42344229
}

‎cpp2rust/converter/converter.h‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,8 +365,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
365365
if (ty->isBuiltinType() || ty->isEnumeralType()) {
366366
return true;
367367
}
368-
if (auto *record = ty->getAsRecordDecl()) {
369-
return RecordDerivesCopy(record);
368+
if (ty->getAsRecordDecl()) {
369+
return RecordDerivesCopy(ty);
370370
}
371371
return false;
372372
}
@@ -791,7 +791,7 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
791791

792792
virtual bool TypeDerivesDefault(clang::QualType qual_type);
793793

794-
bool RecordDerivesCopy(const clang::RecordDecl *decl);
794+
bool RecordDerivesCopy(clang::QualType type);
795795

796796
bool IsPassThroughRule(clang::Expr *expr) const;
797797

‎cpp2rust/converter/converter_lib.cpp‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,14 @@ bool IsUserDefinedDecl(const clang::Decl *decl) {
274274
})) {
275275
return false;
276276
}
277+
} else if (auto tag = llvm::dyn_cast<clang::TagDecl>(decl)) {
278+
if (auto definition = tag->getDefinition()) {
279+
decl = definition;
280+
} else if (llvm::any_of(tag->redecls(), [&](auto redecl) {
281+
return src_mgr.isInSystemHeader(redecl->getLocation());
282+
})) {
283+
return false;
284+
}
277285
}
278286
auto src_loc = decl->getLocation();
279287
if (auto *spec =

‎cpp2rust/converter/models/boxed_vars.cpp‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,9 @@ class AddressTakenVisitor
260260
}
261261

262262
void AddressTaken(const clang::ValueDecl *decl) {
263+
if (!IsUserDefinedDecl(decl)) {
264+
return;
265+
}
263266
if (auto *var = clang::dyn_cast<clang::VarDecl>(decl);
264267
var && CanUnbox(ctx_, var)) {
265268
address_taken_.insert(var);

‎cpp2rust/converter/rules/decls.cpp‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <optional>
1414
#include <vector>
1515

16+
#include "converter/converter_lib.h"
17+
1618
namespace cpp2rust::RuleDecls {
1719

1820
const clang::Expr *SkipImplicit(const clang::Expr *expr) {
@@ -103,4 +105,72 @@ DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params,
103105
return std::vector<clang::TemplateArgument>(deduced.begin(), deduced.end());
104106
}
105107

108+
bool IsInternal(const clang::NamedDecl *decl) {
109+
if (decl->getAccess() == clang::AS_private ||
110+
decl->getAccess() == clang::AS_protected) {
111+
return true;
112+
}
113+
auto &opts = decl->getASTContext().getLangOpts();
114+
if (decl->isReserved(opts) != clang::ReservedIdentifierStatus::NotReserved) {
115+
return true;
116+
}
117+
for (auto context = decl->getDeclContext(); context;
118+
context = context->getParent()) {
119+
if (context->isInlineNamespace()) {
120+
continue;
121+
}
122+
auto named = llvm::dyn_cast<clang::NamedDecl>(context);
123+
if (named && named->getIdentifier() &&
124+
named->isReserved(opts) !=
125+
clang::ReservedIdentifierStatus::NotReserved) {
126+
return true;
127+
}
128+
}
129+
return false;
130+
}
131+
132+
clang::QualType PeelSugar(clang::ASTContext &ctx, clang::QualType type) {
133+
while (!llvm::isa<clang::TypedefType, clang::PredefinedSugarType>(
134+
type.getTypePtr()) &&
135+
type != type.getSingleStepDesugaredType(ctx)) {
136+
type = type.getSingleStepDesugaredType(ctx);
137+
}
138+
return type;
139+
}
140+
141+
const clang::Type *GetSugar(clang::QualType type) {
142+
if (auto typeof_type =
143+
llvm::dyn_cast<clang::TypeOfExprType>(type.getTypePtr())) {
144+
type = typeof_type->getUnderlyingExpr()->getType();
145+
}
146+
if (llvm::isa<clang::TypedefType, clang::PredefinedSugarType>(
147+
type.getTypePtr())) {
148+
return type.getTypePtr();
149+
}
150+
return nullptr;
151+
}
152+
153+
clang::QualType SkipInternalTypedefs(clang::ASTContext &ctx,
154+
clang::QualType use) {
155+
auto cvr = use.getLocalCVRQualifiers();
156+
auto type = PeelSugar(ctx, use);
157+
while (auto typedef_type =
158+
llvm::dyn_cast<clang::TypedefType>(type.getTypePtr())) {
159+
auto decl = typedef_type->getDecl();
160+
if (!IsInternal(decl) && !IsUserDefinedDecl(decl)) {
161+
break;
162+
}
163+
type = PeelSugar(ctx, typedef_type->desugar());
164+
cvr |= type.getLocalCVRQualifiers();
165+
}
166+
return type.withCVRQualifiers(cvr);
167+
}
168+
169+
const clang::TypedefNameDecl *SpelledTypedef(clang::ASTContext &ctx,
170+
clang::QualType use) {
171+
auto sugar = GetSugar(PeelSugar(ctx, use));
172+
auto typedef_type = llvm::dyn_cast_or_null<clang::TypedefType>(sugar);
173+
return typedef_type ? typedef_type->getDecl() : nullptr;
174+
}
175+
106176
} // namespace cpp2rust::RuleDecls

‎cpp2rust/converter/rules/decls.h‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,16 @@ std::optional<std::vector<clang::TemplateArgument>>
4646
DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params,
4747
clang::QualType pattern, clang::QualType actual);
4848

49+
bool IsInternal(const clang::NamedDecl *decl);
50+
51+
clang::QualType PeelSugar(clang::ASTContext &ctx, clang::QualType type);
52+
53+
const clang::Type *GetSugar(clang::QualType type);
54+
55+
clang::QualType SkipInternalTypedefs(clang::ASTContext &ctx,
56+
clang::QualType use);
57+
58+
const clang::TypedefNameDecl *SpelledTypedef(clang::ASTContext &ctx,
59+
clang::QualType use);
60+
4961
} // namespace cpp2rust::RuleDecls

‎cpp2rust/converter/rules/registry.cpp‎

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "converter/rules/registry.h"
55

6+
#include <clang/AST/Attr.h>
67
#include <clang/AST/DeclCXX.h>
78
#include <clang/AST/DeclTemplate.h>
89
#include <clang/Basic/SourceManager.h>
@@ -273,22 +274,23 @@ struct TypeRuleMatch {
273274

274275
TypeRuleMatch findType(clang::QualType use) {
275276
TypeRuleMatch best;
276-
auto consider = [&](const RuleKeys::TypeKey &key) {
277-
auto [begin, end] = types_.equal_range(key);
278-
for (auto it = begin; it != end; ++it) {
279-
auto match = AstMatcher::MatchType(*sema_, use, it->second.decl);
280-
if (!match) {
281-
continue;
282-
}
283-
if (best.rule_decl) {
284-
if (match->depth > best.match.depth) {
277+
auto &ctx = sema_->Context;
278+
auto consider = [&](clang::QualType type, bool templates) {
279+
for (auto key : RuleKeys::GetTypeKeys(ctx, type)) {
280+
auto [begin, end] = types_.equal_range(key);
281+
for (auto it = begin; it != end; ++it) {
282+
if (!templates && llvm::isa<clang::TemplateDecl>(it->second.decl)) {
285283
continue;
286284
}
287-
if (match->depth == best.match.depth) {
285+
auto match = AstMatcher::MatchType(*sema_, type, it->second.decl);
286+
if (!match) {
287+
continue;
288+
}
289+
if (best.rule_decl) {
288290
auto better = AstMatcher::MoreSpecializedType(*sema_, it->second.decl,
289291
best.rule_decl->decl);
290292
if (!better) {
291-
use.dump(llvm::errs(), sema_->Context);
293+
type.dump(llvm::errs(), ctx);
292294
it->second.decl->dump(llvm::errs());
293295
best.rule_decl->decl->dump(llvm::errs());
294296
llvm::report_fatal_error(
@@ -298,12 +300,31 @@ TypeRuleMatch findType(clang::QualType use) {
298300
continue;
299301
}
300302
}
303+
best = {&it->second, *std::move(match)};
301304
}
302-
best = {&it->second, *std::move(match)};
303305
}
304306
};
305-
for (auto key : RuleKeys::GetTypeKeys(sema_->Context, use)) {
306-
consider(key);
307+
auto skipped = RuleDecls::SkipInternalTypedefs(ctx, use);
308+
if (RuleDecls::SpelledTypedef(ctx, skipped) !=
309+
RuleDecls::SpelledTypedef(ctx, use)) {
310+
consider(use, /*templates=*/false);
311+
if (best.rule_decl) {
312+
return best;
313+
}
314+
}
315+
use = skipped;
316+
if (auto tag = use->getAsTagDecl();
317+
tag &&
318+
(IsUserDefinedDecl(tag) || tag->hasAttr<clang::TransparentUnionAttr>())) {
319+
return best;
320+
}
321+
consider(use, /*templates=*/true);
322+
if (!best.rule_decl) {
323+
auto spelled = RuleDecls::SpelledTypedef(ctx, use);
324+
if (spelled && !IsUserDefinedDecl(spelled)) {
325+
use.dump(llvm::errs(), ctx);
326+
llvm::report_fatal_error("typedef has no type rule");
327+
}
307328
}
308329
return best;
309330
}
@@ -401,8 +422,11 @@ Matcher::Match<TranslationRule::TypeRule> Search(clang::ASTContext &ctx,
401422
if (!match.rule_decl) {
402423
return {};
403424
}
404-
return {&match.rule_decl->rule,
405-
getBindings(match.rule_decl->decl, match.match.args)};
425+
auto bindings = getBindings(match.rule_decl->decl, match.match.args);
426+
if (auto generic = match.rule_decl->rule.generic) {
427+
return Search(ctx, bindings.at(generic - 1).getAsType());
428+
}
429+
return {&match.rule_decl->rule, std::move(bindings)};
406430
}
407431

408432
const TranslationRule::ExprRule *GetExprRule(clang::ASTContext &ctx,

‎cpp2rust/converter/rules/rule_keys.cpp‎

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ const clang::Decl *getParent(clang::QualType type) {
4242
llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(record)) {
4343
return spec->getSpecializedTemplate()->getCanonicalDecl();
4444
}
45+
if (auto tmpl = record->getDescribedClassTemplate()) {
46+
return tmpl->getCanonicalDecl();
47+
}
4548
return record->getCanonicalDecl();
4649
}
4750

@@ -277,21 +280,17 @@ std::vector<TypeKey> GetTypeKeys(clang::ASTContext &ctx, clang::QualType use) {
277280
record && !use->isDependentType() && !IsUserDefinedDecl(record)) {
278281
keys.push_back(kAnyClass);
279282
}
280-
for (auto type = use;; type = type.getSingleStepDesugaredType(ctx)) {
281-
if (auto typedef_type =
282-
llvm::dyn_cast<clang::TypedefType>(type.getTypePtr())) {
283-
if (auto owner = llvm::dyn_cast<clang::CXXRecordDecl>(
284-
typedef_type->getDecl()->getDeclContext())) {
285-
auto key = GetTypeKey(ctx.getCanonicalTagType(owner));
286-
if (key && !llvm::is_contained(keys, *key)) {
287-
keys.push_back(*key);
288-
}
283+
if (auto typedef_type =
284+
llvm::dyn_cast<clang::TypedefType>(use.getTypePtr())) {
285+
if (auto owner = llvm::dyn_cast<clang::CXXRecordDecl>(
286+
typedef_type->getDecl()->getDeclContext())) {
287+
auto key = GetTypeKey(ctx.getCanonicalTagType(owner));
288+
if (key && !llvm::is_contained(keys, *key)) {
289+
keys.push_back(*key);
289290
}
290291
}
291-
if (type.getSingleStepDesugaredType(ctx) == type) {
292-
return keys;
293-
}
294292
}
293+
return keys;
295294
}
296295

297296
std::optional<ExprKey> GetDeclKey(const clang::NamedDecl *decl) {

0 commit comments

Comments
 (0)