Skip to content

Commit 5c45615

Browse files
authored
Merge pull request #1080 from flang-compiler/jpr-parentheses-in-call-2
Ensure temporaries are passed in calls for parenthesized arguments
2 parents a1ced48 + f72aec4 commit 5c45615

File tree

2 files changed

+292
-4
lines changed

2 files changed

+292
-4
lines changed

flang/lib/Lower/ConvertExpr.cpp

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1977,6 +1977,73 @@ class ScalarExprLowering {
19771977
return call.getResult(0);
19781978
}
19791979

1980+
/// Is this a variable wrapped in parentheses ?
1981+
template <typename A>
1982+
bool isParenthesizedVariable(const A &) {
1983+
return false;
1984+
}
1985+
template <typename T>
1986+
bool isParenthesizedVariable(const Fortran::evaluate::Expr<T> &expr) {
1987+
using ExprVariant = decltype(Fortran::evaluate::Expr<T>::u);
1988+
using Parentheses = Fortran::evaluate::Parentheses<T>;
1989+
if constexpr (Fortran::common::HasMember<Parentheses, ExprVariant>) {
1990+
if (const auto *parentheses = std::get_if<Parentheses>(&expr.u))
1991+
return Fortran::evaluate::IsVariable(parentheses->left());
1992+
return false;
1993+
} else {
1994+
return std::visit(
1995+
[&](const auto &x) { return isParenthesizedVariable(x); }, expr.u);
1996+
}
1997+
}
1998+
1999+
/// Like genExtAddr, but ensure the address returned is a temporary even if \p
2000+
/// expr is variable inside parentheses.
2001+
ExtValue genTempExtAddr(const Fortran::lower::SomeExpr &expr) {
2002+
// In general, genExtAddr might not create a temp for variable inside
2003+
// parentheses to avoid creating array temporary in sub-expressions. It only
2004+
// ensures the sub-expression is not re-associated with other parts of the
2005+
// expression. In the call semantics, there is a difference between expr and
2006+
// variable (see R1524). For expressions, a variable storage must not be
2007+
// argument associated since it could be modified inside the call, or the
2008+
// variable could also be modified by other means during the call.
2009+
if (!isParenthesizedVariable(expr))
2010+
return genExtAddr(expr);
2011+
if (expr.Rank() > 0)
2012+
return asArray(expr);
2013+
auto loc = getLoc();
2014+
return genExtValue(expr).match(
2015+
[&](const fir::CharBoxValue &boxChar) -> ExtValue {
2016+
return fir::factory::CharacterExprHelper{builder, loc}.createTempFrom(
2017+
boxChar);
2018+
},
2019+
[&](const fir::UnboxedValue &v) -> ExtValue {
2020+
auto type = v.getType();
2021+
mlir::Value value = v;
2022+
if (fir::isa_ref_type(type))
2023+
value = builder.create<fir::LoadOp>(loc, value);
2024+
auto temp = builder.createTemporary(loc, value.getType());
2025+
builder.create<fir::StoreOp>(loc, value, temp);
2026+
return temp;
2027+
},
2028+
[&](const fir::BoxValue &x) -> ExtValue {
2029+
// Derived type scalar that may be polymorphic.
2030+
assert(!x.hasRank() && x.isDerived());
2031+
if (x.isDerivedWithLengthParameters())
2032+
fir::emitFatalError(
2033+
loc, "making temps for derived type with length parameters");
2034+
// TODO: polymorphic aspects should be kept but for now the temp
2035+
// created always has the declared type.
2036+
auto var = fir::getBase(fir::factory::readBoxValue(builder, loc, x));
2037+
auto value = builder.create<fir::LoadOp>(loc, var);
2038+
auto temp = builder.createTemporary(loc, value.getType());
2039+
builder.create<fir::StoreOp>(loc, value, temp);
2040+
return temp;
2041+
},
2042+
[&](const auto &) -> ExtValue {
2043+
fir::emitFatalError(loc, "expr is not a scalar value");
2044+
});
2045+
}
2046+
19802047
/// Lower a non-elemental procedure reference.
19812048
ExtValue genRawProcedureRef(const Fortran::evaluate::ProcedureRef &procRef,
19822049
llvm::Optional<mlir::Type> resultType) {
@@ -2049,11 +2116,11 @@ class ScalarExprLowering {
20492116
mutableModifiedByCall.emplace_back(std::move(mutableBox));
20502117
continue;
20512118
}
2052-
2119+
const bool actualArgIsVariable = Fortran::evaluate::IsVariable(*expr);
20532120
if (arg.passBy == PassBy::BaseAddress || arg.passBy == PassBy::BoxChar) {
20542121
auto argAddr = [&]() -> ExtValue {
20552122
ExtValue baseAddr;
2056-
if (Fortran::evaluate::IsVariable(*expr) && expr->Rank() > 0) {
2123+
if (actualArgIsVariable && expr->Rank() > 0) {
20572124
auto box = genBoxArg(*expr);
20582125
if (!Fortran::evaluate::IsSimplyContiguous(
20592126
*expr, converter.getFoldingContext())) {
@@ -2070,8 +2137,12 @@ class ScalarExprLowering {
20702137
// Contiguous: just use the box we created above!
20712138
// This gets "unboxed" below, if needed.
20722139
baseAddr = box;
2073-
} else
2140+
} else if (actualArgIsVariable) {
20742141
baseAddr = genExtAddr(*expr);
2142+
} else {
2143+
// Make sure a variable address is not passed.
2144+
baseAddr = genTempExtAddr(*expr);
2145+
}
20752146

20762147
// Scalar and contiguous expressions may be lowered to a fir.box,
20772148
// either to account for potential polymorphism, or because lowering
@@ -2126,7 +2197,11 @@ class ScalarExprLowering {
21262197
caller.placeInput(arg, builder.create<mlir::SelectOp>(
21272198
loc, isAllocated, convertedBox, absent));
21282199
} else {
2129-
auto box = builder.createBox(loc, genBoxArg(*expr));
2200+
// Make sure a variable address is only passed if the expression is
2201+
// actually a variable.
2202+
auto box = actualArgIsVariable
2203+
? builder.createBox(loc, genBoxArg(*expr))
2204+
: builder.createBox(getLoc(), genTempExtAddr(*expr));
21302205
caller.placeInput(arg, box);
21312206
}
21322207
} else if (arg.passBy == PassBy::AddressAndLength) {

0 commit comments

Comments
 (0)