@@ -1977,6 +1977,73 @@ class ScalarExprLowering {
1977
1977
return call.getResult (0 );
1978
1978
}
1979
1979
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
+
1980
2047
// / Lower a non-elemental procedure reference.
1981
2048
ExtValue genRawProcedureRef (const Fortran::evaluate::ProcedureRef &procRef,
1982
2049
llvm::Optional<mlir::Type> resultType) {
@@ -2049,11 +2116,11 @@ class ScalarExprLowering {
2049
2116
mutableModifiedByCall.emplace_back (std::move (mutableBox));
2050
2117
continue ;
2051
2118
}
2052
-
2119
+ const bool actualArgIsVariable = Fortran::evaluate::IsVariable (*expr);
2053
2120
if (arg.passBy == PassBy::BaseAddress || arg.passBy == PassBy::BoxChar) {
2054
2121
auto argAddr = [&]() -> ExtValue {
2055
2122
ExtValue baseAddr;
2056
- if (Fortran::evaluate::IsVariable (*expr) && expr->Rank () > 0 ) {
2123
+ if (actualArgIsVariable && expr->Rank () > 0 ) {
2057
2124
auto box = genBoxArg (*expr);
2058
2125
if (!Fortran::evaluate::IsSimplyContiguous (
2059
2126
*expr, converter.getFoldingContext ())) {
@@ -2070,8 +2137,12 @@ class ScalarExprLowering {
2070
2137
// Contiguous: just use the box we created above!
2071
2138
// This gets "unboxed" below, if needed.
2072
2139
baseAddr = box;
2073
- } else
2140
+ } else if (actualArgIsVariable) {
2074
2141
baseAddr = genExtAddr (*expr);
2142
+ } else {
2143
+ // Make sure a variable address is not passed.
2144
+ baseAddr = genTempExtAddr (*expr);
2145
+ }
2075
2146
2076
2147
// Scalar and contiguous expressions may be lowered to a fir.box,
2077
2148
// either to account for potential polymorphism, or because lowering
@@ -2126,7 +2197,11 @@ class ScalarExprLowering {
2126
2197
caller.placeInput (arg, builder.create <mlir::SelectOp>(
2127
2198
loc, isAllocated, convertedBox, absent));
2128
2199
} 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));
2130
2205
caller.placeInput (arg, box);
2131
2206
}
2132
2207
} else if (arg.passBy == PassBy::AddressAndLength) {
0 commit comments