Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <memory>
#include <utility>
#define ANNOTATE(property) __attribute__((annotate(property)))
struct Cell {
int f;
} ANNOTATE("GC Thing");
namespace World {
namespace NS {
struct Unsafe {
int g;
~Unsafe() { asm(""); }
} ANNOTATE("Invalidated by GC") ANNOTATE("GC Pointer or Reference");
} // namespace NS
} // namespace World
extern void GC() ANNOTATE("GC Call");
extern void invisible();
void GC() {
// If the implementation is too trivial, the function body won't be emitted at
// all.
asm("");
invisible();
}
struct GCOnDestruction {
~GCOnDestruction() { GC(); }
};
struct NoGCOnDestruction {
~NoGCOnDestruction() { asm(""); }
};
extern void usecell(Cell*);
Cell* cell() {
static Cell c;
return &c;
}
template <typename T, typename U>
struct SimpleTemplate {
int member;
};
template <typename T, typename U>
class ANNOTATE("moz_inherit_type_annotations_from_template_args") Container {
public:
template <typename V, typename W>
void foo(V& v, W& w) {
class InnerClass {};
InnerClass xxx;
return;
}
struct Entry {
T t;
U u;
}* ent;
};
Cell* f() {
Container<int, double> c1;
Container<SimpleTemplate<int, int>, SimpleTemplate<double, double>> c2;
Container<Container<int, double>, Container<float, float>> c3;
Container<Container<SimpleTemplate<int, int>, float>,
Container<float, SimpleTemplate<char, char>>>
c4;
return nullptr;
}
// Define a set of classes for verifying that there is no infinite loop
// when a class contains itself via mozilla::UniquePtr.
namespace mozilla {
template <typename A>
struct JustAField {
A field;
// Hack to allow UniquePtr and SimpleUniquePtr to be swapped.
A& operator->() { return field; }
};
template <typename T>
struct UniquePtr {
JustAField<T*> holder;
};
// This did not trigger the infinite loop, because the pointer here
// caused the UniquePtr special handling to be skipped. It requires
// the above definition to be triggered, which matches the actual
// implementation (JustAField maps to CompactPair, more or less).
// The bugfix for the infinite loop also drops this requirement, so
// now this *would* trigger the bug if it weren't fixed in the same
// commit.
template <typename T>
struct SimpleUniquePtr {
T* holder;
};
} // namespace mozilla
class Recursive {
public:
using EntryMap = Container<Cell*, Recursive>;
mozilla::UniquePtr<EntryMap> entries;
};
void rvalue_ref(World::NS::Unsafe&& arg1) { GC(); }
void ref(const World::NS::Unsafe& arg2) {
Recursive* foo;
// Must actually use a type for the compiler to instantiate the
// template specializations.
foo->entries.holder->ent;
GC();
static int use = arg2.g;
}
// A function that consumes a parameter, but only if passed by rvalue reference.
extern void eat(World::NS::Unsafe&&);
extern void eat(World::NS::Unsafe&);
void rvalue_ref_ok() {
World::NS::Unsafe unsafe1;
eat(std::move(unsafe1));
GC();
}
void rvalue_ref_not_ok() {
World::NS::Unsafe unsafe2;
eat(unsafe2);
GC();
}
void rvalue_ref_arg_ok(World::NS::Unsafe&& unsafe3) {
eat(std::move(unsafe3));
GC();
}
void rvalue_ref_arg_not_ok(World::NS::Unsafe&& unsafe4) {
eat(unsafe4);
GC();
}
void shared_ptr_hazard() {
Cell* unsafe5 = f();
{ auto p = std::make_shared<GCOnDestruction>(); }
usecell(unsafe5);
}
void shared_ptr_no_hazard() {
Cell* safe6 = f();
{ auto p = std::make_shared<NoGCOnDestruction>(); }
usecell(safe6);
}