[flang] Fix frontend build with -DBUILD_SHARED_LIBS=On

Fix fronted shared library builds by eliminating dependences of
the parser on other component libraries, moving some code around that
wasn't in the right library, and making some dependences
explicit in the CMakeLists.txt files.  The lowering library
does not yet build as a shared library due to some undefined
names.

Reviewed By: tskeith

Differential Revision: https://reviews.llvm.org/D83515
This commit is contained in:
peter klausler 2020-07-09 11:08:41 -07:00
parent 8be204fe75
commit 8a8bb078a3
20 changed files with 104 additions and 67 deletions

View File

@ -122,20 +122,49 @@ private:
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_

View File

@ -195,6 +195,7 @@ public:
: 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_; }

View File

@ -841,6 +841,7 @@ struct GenericExprWrapper {
explicit GenericExprWrapper(std::optional<Expr<SomeType>> &&x)
: v{std::move(x)} {}
~GenericExprWrapper();
static void Deleter(GenericExprWrapper *);
std::optional<Expr<SomeType>> v; // vacant if error
};
@ -849,6 +850,7 @@ struct GenericAssignmentWrapper {
GenericAssignmentWrapper() {}
explicit GenericAssignmentWrapper(Assignment &&x) : v{std::move(x)} {}
~GenericAssignmentWrapper();
static void Deleter(GenericAssignmentWrapper *);
std::optional<Assignment> v; // vacant if error
};

View File

@ -908,6 +908,7 @@ bool IsProcedure(const Symbol &);
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 &);

View File

@ -1395,8 +1395,7 @@ WRAPPER_CLASS(ContiguousStmt, std::list<ObjectName>);
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 |
@ -1919,8 +1918,8 @@ struct DeallocateStmt {
// 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;
};
@ -3140,8 +3139,7 @@ struct FunctionReference {
// 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
};

View File

@ -70,7 +70,8 @@ class IntrinsicProcTable;
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); }

View File

@ -85,7 +85,6 @@ bool IsPointerDummy(const Symbol &);
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);

View File

@ -41,7 +41,6 @@ add_flang_library(FortranEvaluate
LINK_LIBS
FortranCommon
FortranDecimal
FortranSemantics
FortranParser
${LIBPGMATH}

View File

@ -212,6 +212,7 @@ int ProcedureRef::Rank() const {
ProcedureRef::~ProcedureRef() {}
void ProcedureRef::Deleter(ProcedureRef *p) { delete p; }
FOR_EACH_SPECIFIC_TYPE(template class FunctionRef, )
} // namespace Fortran::evaluate
DEFINE_DELETER(Fortran::evaluate::ProcedureRef)

View File

@ -223,8 +223,14 @@ StructureConstructor &StructureConstructor::Add(
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; },
@ -243,5 +249,3 @@ std::optional<Expr<SubscriptInteger>> Expr<SomeCharacter>::LEN() const {
INSTANTIATE_EXPRESSION_TEMPLATES
} // namespace Fortran::evaluate
DEFINE_DELETER(Fortran::evaluate::GenericExprWrapper)
DEFINE_DELETER(Fortran::evaluate::GenericAssignmentWrapper)

View File

@ -1026,6 +1026,13 @@ bool IsDummy(const Symbol &symbol) {
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(); });

View File

@ -22,6 +22,10 @@ add_flang_library(FortranLower
LINK_LIBS
FIROptimizer
${dialect_libs}
FortranCommon
FortranParser
FortranEvaluate
FortranSemantics
MLIRAffineToStandard
MLIRLLVMIR
MLIRSCFToStandard

View File

@ -14,16 +14,6 @@
#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
@ -258,6 +248,3 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Name &x) {
}
} // namespace Fortran::parser
template class std::unique_ptr<Fortran::evaluate::GenericExprWrapper>;
template class std::unique_ptr<Fortran::evaluate::GenericAssignmentWrapper>;

View File

@ -44,6 +44,7 @@ add_flang_library(FortranSemantics
LINK_LIBS
FortranCommon
FortranParser
FortranEvaluate
LINK_COMPONENTS

View File

@ -2031,8 +2031,10 @@ void ExpressionAnalyzer::Analyze(const parser::CallStmt &callStmt) {
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);
}
}
}
@ -2044,7 +2046,8 @@ const Assignment *ExpressionAnalyzer::Analyze(const parser::AssignmentStmt &x) {
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{
@ -2052,8 +2055,9 @@ const Assignment *ExpressionAnalyzer::Analyze(const parser::AssignmentStmt &x) {
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);
@ -2065,7 +2069,8 @@ const Assignment *ExpressionAnalyzer::Analyze(
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{
@ -2092,8 +2097,9 @@ const Assignment *ExpressionAnalyzer::Analyze(
},
},
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);
@ -2934,7 +2940,7 @@ std::optional<ActualArgument> ArgumentAnalyzer::AnalyzeExpr(
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 {

View File

@ -1217,13 +1217,6 @@ const Symbol *FindImmediateComponent(const DerivedTypeSpec &type,
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()}) {

View File

@ -9,25 +9,19 @@
// 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)

View File

@ -1,4 +1,5 @@
set(LLVM_LINK_COMPONENTS
FrontendOpenMP
Support
)
add_flang_tool(f18

View File

@ -4,6 +4,10 @@ add_library(FortranEvaluateTesting
fp-testing.cpp
)
target_link_libraries(FortranEvaluateTesting
LLVMSupport
)
add_executable(leading-zero-bit-count-test
leading-zero-bit-count.cpp
)

View File

@ -8,6 +8,11 @@ add_library(RuntimeTesting
)
llvm_update_compile_flags(RuntimeTesting)
target_link_libraries(RuntimeTesting
FortranRuntime
LLVMSupport
)
add_executable(format-test
format.cpp
)