template <typename A> using CopyableIndirection = Indirection<A, true>;
-// For use with std::unique_ptr<> when declaring owning pointers to
-// forward-referenced types, here's a minimal custom deleter that avoids
-// some of the drama with std::default_delete<>. Invoke DEFINE_DELETER()
-// later in exactly one C++ source file where a complete definition of the
-// type is visible. Be advised, std::unique_ptr<> does not have copy
-// semantics; if you need ownership, copy semantics, and nullability,
-// std::optional<CopyableIndirection<>> works.
-template <typename A> class Deleter {
+// A variation of std::unique_ptr<> with a reified deletion routine.
+// Used to avoid dependence cycles between shared libraries.
+template <typename A> class ForwardOwningPointer {
public:
- void operator()(A *) const;
+ ForwardOwningPointer() {}
+ ForwardOwningPointer(A *p, void (*del)(A *)) : p_{p}, deleter_{del} {}
+ ForwardOwningPointer(ForwardOwningPointer &&that)
+ : p_{that.p_}, deleter_{that.deleter_} {
+ that.p_ = nullptr;
+ }
+ ForwardOwningPointer &operator=(ForwardOwningPointer &&that) {
+ p_ = that.p_;
+ that.p_ = nullptr;
+ deleter_ = that.deleter_;
+ return *this;
+ }
+ ~ForwardOwningPointer() {
+ if (p_) {
+ deleter_(p_);
+ }
+ }
+
+ A &operator*() const { return *p_; }
+ A *operator->() const { return p_; }
+ operator bool() const { return p_ != nullptr; }
+ A *get() { return p_; }
+ A *release() {
+ A *result{p_};
+ p_ = nullptr;
+ return result;
+ }
+
+ void Reset(A *p, void (*del)(A *)) {
+ if (p_) {
+ deleter_(p_);
+ }
+ p_ = p;
+ deleter_ = del;
+ }
+
+private:
+ A *p_{nullptr};
+ void (*deleter_)(A *){nullptr};
};
} // namespace Fortran::common
-#define DEFINE_DELETER(A) \
- template <> void Fortran::common::Deleter<A>::operator()(A *p) const { \
- delete p; \
- }
#endif // FORTRAN_COMMON_INDIRECTION_H_
: proc_{std::move(p)}, arguments_{std::move(a)},
hasAlternateReturns_{hasAlternateReturns} {}
~ProcedureRef();
+ static void Deleter(ProcedureRef *);
ProcedureDesignator &proc() { return proc_; }
const ProcedureDesignator &proc() const { return proc_; }
explicit GenericExprWrapper(std::optional<Expr<SomeType>> &&x)
: v{std::move(x)} {}
~GenericExprWrapper();
+ static void Deleter(GenericExprWrapper *);
std::optional<Expr<SomeType>> v; // vacant if error
};
GenericAssignmentWrapper() {}
explicit GenericAssignmentWrapper(Assignment &&x) : v{std::move(x)} {}
~GenericAssignmentWrapper();
+ static void Deleter(GenericAssignmentWrapper *);
std::optional<Assignment> v; // vacant if error
};
bool IsProcedurePointer(const Symbol &);
bool IsSaved(const Symbol &); // saved implicitly or explicitly
bool IsDummy(const Symbol &);
+bool IsFunctionResult(const Symbol &);
// Follow use, host, and construct assocations to a variable, if any.
const Symbol *GetAssociationRoot(const Symbol &);
using ConstantSubobject = Constant<common::Indirection<Designator>>;
// Represents an analyzed expression
-using TypedExpr = std::unique_ptr<evaluate::GenericExprWrapper,
- common::Deleter<evaluate::GenericExprWrapper>>;
+using TypedExpr = common::ForwardOwningPointer<evaluate::GenericExprWrapper>;
// R845 data-stmt-constant ->
// scalar-constant | scalar-constant-subobject |
// R1032 assignment-stmt -> variable = expr
struct AssignmentStmt {
TUPLE_CLASS_BOILERPLATE(AssignmentStmt);
- using TypedAssignment = std::unique_ptr<evaluate::GenericAssignmentWrapper,
- common::Deleter<evaluate::GenericAssignmentWrapper>>;
+ using TypedAssignment =
+ common::ForwardOwningPointer<evaluate::GenericAssignmentWrapper>;
mutable TypedAssignment typedAssignment;
std::tuple<Variable, Expr> t;
};
// R1521 call-stmt -> CALL procedure-designator [( [actual-arg-spec-list] )]
struct CallStmt {
WRAPPER_CLASS_BOILERPLATE(CallStmt, Call);
- mutable std::unique_ptr<evaluate::ProcedureRef,
- common::Deleter<evaluate::ProcedureRef>>
+ mutable common::ForwardOwningPointer<evaluate::ProcedureRef>
typedCall; // filled by semantics
};
struct SetExprHelper {
explicit SetExprHelper(GenericExprWrapper &&expr) : expr_{std::move(expr)} {}
void Set(parser::TypedExpr &x) {
- x.reset(new GenericExprWrapper{std::move(expr_)});
+ x.Reset(new GenericExprWrapper{std::move(expr_)},
+ evaluate::GenericExprWrapper::Deleter);
}
void Set(const parser::Expr &x) { Set(x.typedExpr); }
void Set(const parser::Variable &x) { Set(x.typedExpr); }
bool IsBindCProcedure(const Symbol &);
bool IsBindCProcedure(const Scope &);
bool IsProcName(const Symbol &); // proc-name
-bool IsFunctionResult(const Symbol &);
bool IsFunctionResultWithSameNameAsFunction(const Symbol &);
bool IsExtensibleType(const DerivedTypeSpec *);
bool IsBuiltinDerivedType(const DerivedTypeSpec *derived, const char *name);
LINK_LIBS
FortranCommon
FortranDecimal
- FortranSemantics
FortranParser
${LIBPGMATH}
ProcedureRef::~ProcedureRef() {}
+void ProcedureRef::Deleter(ProcedureRef *p) { delete p; }
+
FOR_EACH_SPECIFIC_TYPE(template class FunctionRef, )
} // namespace Fortran::evaluate
-DEFINE_DELETER(Fortran::evaluate::ProcedureRef)
GenericExprWrapper::~GenericExprWrapper() {}
+void GenericExprWrapper::Deleter(GenericExprWrapper *p) { delete p; }
+
GenericAssignmentWrapper::~GenericAssignmentWrapper() {}
+void GenericAssignmentWrapper::Deleter(GenericAssignmentWrapper *p) {
+ delete p;
+}
+
template <TypeCategory CAT> int Expr<SomeKind<CAT>>::GetKind() const {
return std::visit(
[](const auto &kx) { return std::decay_t<decltype(kx)>::Result::kind; },
INSTANTIATE_EXPRESSION_TEMPLATES
} // namespace Fortran::evaluate
-DEFINE_DELETER(Fortran::evaluate::GenericExprWrapper)
-DEFINE_DELETER(Fortran::evaluate::GenericAssignmentWrapper)
symbol.details());
}
+bool IsFunctionResult(const Symbol &symbol) {
+ return (symbol.has<ObjectEntityDetails>() &&
+ symbol.get<ObjectEntityDetails>().isFuncResult()) ||
+ (symbol.has<ProcEntityDetails>() &&
+ symbol.get<ProcEntityDetails>().isFuncResult());
+}
+
int CountLenParameters(const DerivedTypeSpec &type) {
return std::count_if(type.parameters().begin(), type.parameters().end(),
[](const auto &pair) { return pair.second.isLen(); });
LINK_LIBS
FIROptimizer
${dialect_libs}
+ FortranCommon
+ FortranParser
+ FortranEvaluate
+ FortranSemantics
MLIRAffineToStandard
MLIRLLVMIR
MLIRSCFToStandard
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
-// So "delete Expr;" calls an external destructor for its typedExpr.
-namespace Fortran::evaluate {
-struct GenericExprWrapper {
- ~GenericExprWrapper();
-};
-struct GenericAssignmentWrapper {
- ~GenericAssignmentWrapper();
-};
-} // namespace Fortran::evaluate
-
namespace Fortran::parser {
// R867
}
} // namespace Fortran::parser
-
-template class std::unique_ptr<Fortran::evaluate::GenericExprWrapper>;
-template class std::unique_ptr<Fortran::evaluate::GenericAssignmentWrapper>;
LINK_LIBS
FortranCommon
+ FortranParser
FortranEvaluate
LINK_COMPONENTS
if (CheckCall(call.source, *proc, callee->arguments)) {
bool hasAlternateReturns{
callee->arguments.size() < actualArgList.size()};
- callStmt.typedCall.reset(new ProcedureRef{std::move(*proc),
- std::move(callee->arguments), hasAlternateReturns});
+ callStmt.typedCall.Reset(
+ new ProcedureRef{std::move(*proc), std::move(callee->arguments),
+ hasAlternateReturns},
+ ProcedureRef::Deleter);
}
}
}
analyzer.Analyze(std::get<parser::Variable>(x.t));
analyzer.Analyze(std::get<parser::Expr>(x.t));
if (analyzer.fatalErrors()) {
- x.typedAssignment.reset(new GenericAssignmentWrapper{});
+ x.typedAssignment.Reset(
+ new GenericAssignmentWrapper{}, GenericAssignmentWrapper::Deleter);
} else {
std::optional<ProcedureRef> procRef{analyzer.TryDefinedAssignment()};
Assignment assignment{
if (procRef) {
assignment.u = std::move(*procRef);
}
- x.typedAssignment.reset(
- new GenericAssignmentWrapper{std::move(assignment)});
+ x.typedAssignment.Reset(
+ new GenericAssignmentWrapper{std::move(assignment)},
+ GenericAssignmentWrapper::Deleter);
}
}
return common::GetPtrFromOptional(x.typedAssignment->v);
MaybeExpr lhs{Analyze(std::get<parser::DataRef>(x.t))};
MaybeExpr rhs{Analyze(std::get<parser::Expr>(x.t))};
if (!lhs || !rhs) {
- x.typedAssignment.reset(new GenericAssignmentWrapper{});
+ x.typedAssignment.Reset(
+ new GenericAssignmentWrapper{}, GenericAssignmentWrapper::Deleter);
} else {
Assignment assignment{std::move(*lhs), std::move(*rhs)};
std::visit(common::visitors{
},
},
std::get<parser::PointerAssignmentStmt::Bounds>(x.t).u);
- x.typedAssignment.reset(
- new GenericAssignmentWrapper{std::move(assignment)});
+ x.typedAssignment.Reset(
+ new GenericAssignmentWrapper{std::move(assignment)},
+ GenericAssignmentWrapper::Deleter);
}
}
return common::GetPtrFromOptional(x.typedAssignment->v);
const parser::Expr &expr) {
source_.ExtendToCover(expr.source);
if (const Symbol * assumedTypeDummy{AssumedTypeDummy(expr)}) {
- expr.typedExpr.reset(new GenericExprWrapper{});
+ expr.typedExpr.Reset(new GenericExprWrapper{}, GenericExprWrapper::Deleter);
if (allowAssumedType_) {
return ActualArgument{ActualArgument::AssumedType{*assumedTypeDummy}};
} else {
return nullptr;
}
-bool IsFunctionResult(const Symbol &symbol) {
- return (symbol.has<ObjectEntityDetails>() &&
- symbol.get<ObjectEntityDetails>().isFuncResult()) ||
- (symbol.has<ProcEntityDetails>() &&
- symbol.get<ProcEntityDetails>().isFuncResult());
-}
-
bool IsFunctionResultWithSameNameAsFunction(const Symbol &symbol) {
if (IsFunctionResult(symbol)) {
if (const Symbol * function{symbol.owner().symbol()}) {
// The parse tree has slots in which pointers to the results of semantic
// analysis may be placed. When using the parser without the semantics
// libraries, as here, we need to stub out the dependences on the external
-// destructors, which will never actually be called.
-
-#include "flang/Common/indirection.h"
+// deleters, which will never actually be called.
namespace Fortran::evaluate {
struct GenericExprWrapper {
- ~GenericExprWrapper();
+ static void Deleter(GenericExprWrapper *);
};
-GenericExprWrapper::~GenericExprWrapper() {}
+void GenericExprWrapper::Deleter(GenericExprWrapper *) {}
struct GenericAssignmentWrapper {
- ~GenericAssignmentWrapper();
+ static void Deleter(GenericAssignmentWrapper *);
};
-GenericAssignmentWrapper::~GenericAssignmentWrapper() {}
+void GenericAssignmentWrapper::Deleter(GenericAssignmentWrapper *) {}
struct ProcedureRef {
- ~ProcedureRef();
+ static void Deleter(ProcedureRef *);
};
-ProcedureRef::~ProcedureRef() {}
+void ProcedureRef::Deleter(ProcedureRef *) {}
} // namespace Fortran::evaluate
-
-DEFINE_DELETER(Fortran::evaluate::GenericExprWrapper)
-DEFINE_DELETER(Fortran::evaluate::GenericAssignmentWrapper)
-DEFINE_DELETER(Fortran::evaluate::ProcedureRef)
set(LLVM_LINK_COMPONENTS
+ FrontendOpenMP
Support
)
add_flang_tool(f18
fp-testing.cpp
)
+target_link_libraries(FortranEvaluateTesting
+ LLVMSupport
+)
+
add_executable(leading-zero-bit-count-test
leading-zero-bit-count.cpp
)
)
llvm_update_compile_flags(RuntimeTesting)
+target_link_libraries(RuntimeTesting
+ FortranRuntime
+ LLVMSupport
+)
+
add_executable(format-test
format.cpp
)