Skip to content

Commit 1fee5c1

Browse files
Merge branch 'main' into yonah/julia-fix
2 parents 34e0917 + 5226a5a commit 1fee5c1

File tree

20 files changed

+210
-44
lines changed

20 files changed

+210
-44
lines changed

clang-tools-extra/docs/clang-tidy/checks/bugprone/macro-parentheses.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@ with parentheses. This ensures that the argument value is calculated
1919
properly.
2020

2121
This check corresponds to the CERT C Coding Standard rule
22-
`PRE20-C. Macro replacement lists should be parenthesized.
22+
`PRE02-C. Macro replacement lists should be parenthesized.
2323
<https://wiki.sei.cmu.edu/confluence/display/c/PRE02-C.+Macro+replacement+lists+should+be+parenthesized>`_

flang/docs/Extensions.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,10 @@ end
474474
with an optional compilation-time warning. When executed, it
475475
is treated as an 'nX' positioning control descriptor that skips
476476
over the same number of characters, without comparison.
477+
* A passed-object dummy argument for a procedure binding is allowed
478+
to be a pointer so long as it is `INTENT(IN)`.
479+
(This extension is not yet supported for procedure pointer component
480+
interfaces.)
477481

478482
### Extensions supported when enabled by options
479483

flang/include/flang/Lower/CallInterface.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,11 +401,17 @@ class CallerInterface : public CallInterface<CallerInterface> {
401401
llvm_unreachable("getting host associated type in CallerInterface");
402402
}
403403

404+
std::optional<mlir::Value> getOriginalPassArg() const {
405+
return originalPassArg;
406+
}
407+
void setOriginalPassArg(mlir::Value x) { originalPassArg = x; }
408+
404409
private:
405410
/// Check that the input vector is complete.
406411
bool verifyActualInputs() const;
407412
const Fortran::evaluate::ProcedureRef &procRef;
408413
llvm::SmallVector<mlir::Value> actualInputs;
414+
std::optional<mlir::Value> originalPassArg;
409415
};
410416

411417
//===----------------------------------------------------------------------===//

flang/include/flang/Support/Fortran-features.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
5656
IgnoreIrrelevantAttributes, Unsigned, AmbiguousStructureConstructor,
5757
ContiguousOkForSeqAssociation, ForwardRefExplicitTypeDummy,
5858
InaccessibleDeferredOverride, CudaWarpMatchFunction, DoConcurrentOffload,
59-
TransferBOZ, Coarray)
59+
TransferBOZ, Coarray, PointerPassObject)
6060

6161
// Portability and suspicious usage warnings
6262
ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,

flang/lib/Lower/CallInterface.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ bool Fortran::lower::CallerInterface::requireDispatchCall() const {
103103
return true;
104104
}
105105
// calls with PASS attribute have the passed-object already set in its
106-
// arguments. Just check if their is one.
106+
// arguments. Just check if there is one.
107107
std::optional<unsigned> passArg = getPassArgIndex();
108108
if (passArg)
109109
return true;

flang/lib/Lower/ConvertCall.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -673,10 +673,13 @@ Fortran::lower::genCallOpAndResult(
673673
// passed object because interface mismatch issues may have inserted a
674674
// cast to the operand with a different declared type, which would break
675675
// later type bound call resolution in the FIR to FIR pass.
676+
mlir::Value passActual = caller.getInputs()[*passArg];
677+
if (std::optional<mlir::Value> original = caller.getOriginalPassArg())
678+
passActual = *original;
676679
dispatch = fir::DispatchOp::create(
677680
builder, loc, funcType.getResults(), builder.getStringAttr(procName),
678-
caller.getInputs()[*passArg], operands,
679-
builder.getI32IntegerAttr(*passArg), /*arg_attrs=*/nullptr,
681+
passActual, operands, builder.getI32IntegerAttr(*passArg),
682+
/*arg_attrs=*/nullptr,
680683
/*res_attrs=*/nullptr, procAttrs);
681684
} else {
682685
// NOPASS
@@ -1636,8 +1639,12 @@ void prepareUserCallArguments(
16361639
mlir::Location loc = callContext.loc;
16371640
bool mustRemapActualToDummyDescriptors = false;
16381641
fir::FirOpBuilder &builder = callContext.getBuilder();
1642+
std::optional<unsigned> passArg = caller.getPassArgIndex();
1643+
int argIndex = -1;
16391644
for (auto [preparedActual, arg] :
16401645
llvm::zip(loweredActuals, caller.getPassedArguments())) {
1646+
++argIndex;
1647+
bool thisIsPassArg = passArg && argIndex == static_cast<int>(*passArg);
16411648
mlir::Type argTy = callSiteType.getInput(arg.firArgument);
16421649
if (!preparedActual) {
16431650
// Optional dummy argument for which there is no actual argument.
@@ -1750,14 +1757,16 @@ void prepareUserCallArguments(
17501757
continue;
17511758
}
17521759
if (fir::isPointerType(argTy) &&
1753-
!Fortran::evaluate::IsObjectPointer(*expr)) {
1760+
(!Fortran::evaluate::IsObjectPointer(*expr) || thisIsPassArg)) {
17541761
// Passing a non POINTER actual argument to a POINTER dummy argument.
17551762
// Create a pointer of the dummy argument type and assign the actual
17561763
// argument to it.
17571764
auto dataTy = llvm::cast<fir::BaseBoxType>(fir::unwrapRefType(argTy));
17581765
fir::ExtendedValue actualExv = Fortran::lower::convertToAddress(
17591766
loc, callContext.converter, actual, callContext.stmtCtx,
17601767
hlfir::getFortranElementType(dataTy));
1768+
if (thisIsPassArg)
1769+
caller.setOriginalPassArg(fir::getBase(actualExv));
17611770
// If the dummy is an assumed-rank pointer, allocate a pointer
17621771
// descriptor with the actual argument rank (if it is not assumed-rank
17631772
// itself).

flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ class DesignateOpConversion
473473
if (designate.getComponent()) {
474474
mlir::Type baseRecordType = baseEntity.getFortranElementType();
475475
if (fir::isRecordWithTypeParameters(baseRecordType))
476-
TODO(loc, "hlfir.designate with a parametrized derived type base");
476+
TODO(loc, "hlfir.designate with a parameterized derived type base");
477477
fieldIndex = fir::FieldIndexOp::create(
478478
builder, loc, fir::FieldType::get(builder.getContext()),
479479
designate.getComponent().value(), baseRecordType,
@@ -499,7 +499,7 @@ class DesignateOpConversion
499499
return mlir::success();
500500
}
501501
TODO(loc,
502-
"addressing parametrized derived type automatic components");
502+
"addressing parameterized derived type automatic components");
503503
}
504504
baseEleTy = hlfir::getFortranElementType(componentType);
505505
shape = designate.getComponentShape();

flang/lib/Semantics/check-call.cpp

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -610,9 +610,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
610610
!dummy.ignoreTKR.test(common::IgnoreTKR::Contiguous)) {
611611
if (IsPointer(*actualLastSymbol)) {
612612
if (isOkBecauseContiguous) {
613-
context.Warn(
613+
foldingContext.Warn(
614614
common::LanguageFeature::ContiguousOkForSeqAssociation,
615-
messages.at(),
616615
"Element of contiguous pointer array is accepted for storage sequence association"_port_en_US);
617616
} else {
618617
basicError = true;
@@ -623,9 +622,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
623622
} else if (IsAssumedShape(*actualLastSymbol) &&
624623
!dummy.ignoreTKR.test(common::IgnoreTKR::Contiguous)) {
625624
if (isOkBecauseContiguous) {
626-
context.Warn(
625+
foldingContext.Warn(
627626
common::LanguageFeature::ContiguousOkForSeqAssociation,
628-
messages.at(),
629627
"Element of contiguous assumed-shape array is accepted for storage sequence association"_port_en_US);
630628
} else {
631629
basicError = true;
@@ -653,9 +651,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
653651
messages.Say(
654652
"Assumed-rank array may not be associated with a dummy argument that is not assumed-rank"_err_en_US);
655653
} else {
656-
context.Warn(
654+
foldingContext.Warn(
657655
common::LanguageFeature::AssumedRankPassedToNonAssumedRank,
658-
messages.at(),
659656
"Assumed-rank array should not be associated with a dummy argument that is not assumed-rank"_port_en_US);
660657
}
661658
} else if (actualRank == 0) {
@@ -693,7 +690,7 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
693690
static_cast<std::intmax_t>(*actualElements), dummyName,
694691
static_cast<std::intmax_t>(*dummySize));
695692
} else {
696-
context.Warn(common::UsageWarning::ShortArrayActual,
693+
foldingContext.Warn(common::UsageWarning::ShortArrayActual,
697694
"Actual argument has fewer elements remaining in storage sequence (%jd) than %s array (%jd)"_warn_en_US,
698695
static_cast<std::intmax_t>(*actualElements), dummyName,
699696
static_cast<std::intmax_t>(*dummySize));
@@ -711,7 +708,7 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
711708
static_cast<std::intmax_t>(*actualSize), dummyName,
712709
static_cast<std::intmax_t>(*dummySize));
713710
} else {
714-
context.Warn(common::UsageWarning::ShortArrayActual,
711+
foldingContext.Warn(common::UsageWarning::ShortArrayActual,
715712
"Actual argument array has fewer elements (%jd) than %s array (%jd)"_warn_en_US,
716713
static_cast<std::intmax_t>(*actualSize), dummyName,
717714
static_cast<std::intmax_t>(*dummySize));
@@ -826,8 +823,7 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
826823
(actualIsPointer && dummyIsPointer)) &&
827824
evaluate::IsArraySection(actual) && !actualIsContiguous &&
828825
!evaluate::HasVectorSubscript(actual)) {
829-
context.Warn(common::UsageWarning::VolatileOrAsynchronousTemporary,
830-
messages.at(),
826+
foldingContext.Warn(common::UsageWarning::VolatileOrAsynchronousTemporary,
831827
"The array section '%s' should not be associated with %s with %s attribute, unless the dummy is assumed-shape or assumed-rank"_warn_en_US,
832828
actual.AsFortran(), dummyName,
833829
dummyIsAsynchronous ? "ASYNCHRONOUS" : "VOLATILE");
@@ -844,8 +840,7 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
844840
if (copyOutNeeded && !volatileOrAsyncNeedsTempDiagnosticIssued) {
845841
if ((actualIsVolatile || actualIsAsynchronous) &&
846842
(dummyIsVolatile || dummyIsAsynchronous)) {
847-
context.Warn(common::UsageWarning::VolatileOrAsynchronousTemporary,
848-
messages.at(),
843+
foldingContext.Warn(common::UsageWarning::VolatileOrAsynchronousTemporary,
849844
"The actual argument '%s' with %s attribute should not be associated with %s with %s attribute, because a temporary copy is required during the call"_warn_en_US,
850845
actual.AsFortran(), actualIsVolatile ? "VOLATILE" : "ASYNCHRONOUS",
851846
dummyName, dummyIsVolatile ? "VOLATILE" : "ASYNCHRONOUS");
@@ -863,7 +858,7 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
863858
(actualIsPointer && dummyIsPointer)) &&
864859
evaluate::IsArraySection(actual) &&
865860
!evaluate::HasVectorSubscript(actual)) {
866-
context.Warn(common::UsageWarning::Portability, messages.at(),
861+
foldingContext.Warn(common::UsageWarning::Portability,
867862
"The array section '%s' should not be associated with %s with %s attribute, unless the dummy is assumed-shape or assumed-rank"_port_en_US,
868863
actual.AsFortran(), dummyName,
869864
dummyIsAsynchronous ? "ASYNCHRONOUS" : "VOLATILE");
@@ -872,7 +867,7 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
872867
if (copyOutNeeded && !volatileOrAsyncNeedsTempDiagnosticIssued) {
873868
if ((dummyIsVolatile && !actualIsVolatile && !actualIsAsynchronous) ||
874869
(dummyIsAsynchronous && !actualIsVolatile && !actualIsAsynchronous)) {
875-
context.Warn(common::UsageWarning::Portability, messages.at(),
870+
foldingContext.Warn(common::UsageWarning::Portability,
876871
"The actual argument '%s' should not be associated with %s with %s attribute, because a temporary copy is required during the call"_port_en_US,
877872
actual.AsFortran(), dummyName,
878873
dummyIsVolatile ? "VOLATILE" : "ASYNCHRONOUS");
@@ -2437,7 +2432,7 @@ bool CheckArguments(const characteristics::Procedure &proc,
24372432
intrinsic, allowArgumentConversions,
24382433
/*extentErrors=*/true, ignoreImplicitVsExplicit)};
24392434
if (!explicitBuffer.empty()) {
2440-
if (treatingExternalAsImplicit) {
2435+
if (treatingExternalAsImplicit && explicitBuffer.AnyFatalError()) {
24412436
// Combine all messages into one warning
24422437
if (auto *warning{messages.Warn(/*inModuleFile=*/false,
24432438
context.languageFeatures(),

flang/lib/Semantics/check-declarations.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2608,9 +2608,6 @@ void CheckHelper::CheckPassArg(
26082608
if (!passArg.has<ObjectEntityDetails>()) {
26092609
msg = "Passed-object dummy argument '%s' of procedure '%s'"
26102610
" must be a data object"_err_en_US;
2611-
} else if (passArg.attrs().test(Attr::POINTER)) {
2612-
msg = "Passed-object dummy argument '%s' of procedure '%s'"
2613-
" may not have the POINTER attribute"_err_en_US;
26142611
} else if (passArg.attrs().test(Attr::ALLOCATABLE)) {
26152612
msg = "Passed-object dummy argument '%s' of procedure '%s'"
26162613
" may not have the ALLOCATABLE attribute"_err_en_US;
@@ -2620,6 +2617,23 @@ void CheckHelper::CheckPassArg(
26202617
} else if (passArg.Rank() > 0) {
26212618
msg = "Passed-object dummy argument '%s' of procedure '%s'"
26222619
" must be scalar"_err_en_US;
2620+
} else if (passArg.attrs().test(Attr::POINTER)) {
2621+
if (context_.IsEnabled(common::LanguageFeature::PointerPassObject) &&
2622+
IsIntentIn(passArg)) {
2623+
if (proc.has<ProcBindingDetails>()) {
2624+
// Extension: allow a passed object to be an INTENT(IN) POINTER.
2625+
// Only works for TBPs, needs lowering work for proc ptr components.
2626+
Warn(common::LanguageFeature::PointerPassObject, name,
2627+
"Passed-object dummy argument '%s' of procedure '%s' that is an INTENT(IN) POINTER is not standard"_port_en_US,
2628+
*passName, name);
2629+
} else {
2630+
msg =
2631+
"Passed-object dummy argument '%s' of procedure '%s' used as procedure pointer component interface may not have the POINTER attribute"_err_en_US;
2632+
}
2633+
} else {
2634+
msg =
2635+
"Passed-object dummy argument '%s' of procedure '%s' may not have the POINTER attribute unless INTENT(IN)"_err_en_US;
2636+
}
26232637
}
26242638
if (msg) {
26252639
messages_.Say(name, std::move(*msg), passName.value(), name);

flang/lib/Semantics/resolve-names.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7565,12 +7565,14 @@ void DeclarationVisitor::SetType(
75657565
} else if (HadForwardRef(symbol)) {
75667566
// error recovery after use of host-associated name
75677567
} else if (!symbol.test(Symbol::Flag::Implicit)) {
7568-
SayWithDecl(
7569-
name, symbol, "The type of '%s' has already been declared"_err_en_US);
7568+
SayWithDecl(name, symbol,
7569+
"The type of '%s' has already been declared as %s"_err_en_US,
7570+
prevType->AsFortran());
75707571
context().SetError(symbol);
75717572
} else if (type != *prevType) {
75727573
SayWithDecl(name, symbol,
7573-
"The type of '%s' has already been implicitly declared"_err_en_US);
7574+
"The type of '%s' has already been implicitly declared as %s"_err_en_US,
7575+
prevType->AsFortran());
75747576
context().SetError(symbol);
75757577
} else {
75767578
symbol.set(Symbol::Flag::Implicit, false);
@@ -9710,12 +9712,20 @@ void ResolveNamesVisitor::EarlyDummyTypeDeclaration(
97109712
const parser::Statement<common::Indirection<parser::TypeDeclarationStmt>>
97119713
&stmt) {
97129714
context().set_location(stmt.source);
9713-
const auto &[declTypeSpec, attrs, entities] = stmt.statement.value().t;
9715+
const auto &[declTypeSpec, attrs, entities]{stmt.statement.value().t};
97149716
if (const auto *intrin{
97159717
std::get_if<parser::IntrinsicTypeSpec>(&declTypeSpec.u)}) {
97169718
if (const auto *intType{std::get_if<parser::IntegerTypeSpec>(&intrin->u)}) {
97179719
if (const auto &kind{intType->v}) {
9718-
if (!parser::Unwrap<parser::KindSelector::StarSize>(*kind) &&
9720+
if (const auto *call{parser::Unwrap<parser::Call>(*kind)}) {
9721+
if (!std::get<std::list<parser::ActualArgSpec>>(call->t).empty()) {
9722+
// Accept INTEGER(int_ptr_kind()), at least. Don't allow a
9723+
// nonempty argument list, to prevent implicitly typing names
9724+
// that might appear. (TODO: But maybe INTEGER(KIND(n)) after
9725+
// an explicit declaration of 'n' would be useful.)
9726+
return;
9727+
}
9728+
} else if (!parser::Unwrap<parser::KindSelector::StarSize>(*kind) &&
97199729
!parser::Unwrap<parser::IntLiteralConstant>(*kind)) {
97209730
return;
97219731
}

0 commit comments

Comments
 (0)