[flang-commits] [flang] b82a8c3 - [flang] Warn about useless explicit typing of intrinsics

peter klausler via flang-commits flang-commits at lists.llvm.org
Wed Feb 17 13:14:12 PST 2021


Author: peter klausler
Date: 2021-02-17T13:13:59-08:00
New Revision: b82a8c3f231ebdd28f2b3b37142481eec3f43288

URL: https://github.com/llvm/llvm-project/commit/b82a8c3f231ebdd28f2b3b37142481eec3f43288
DIFF: https://github.com/llvm/llvm-project/commit/b82a8c3f231ebdd28f2b3b37142481eec3f43288.diff

LOG: [flang] Warn about useless explicit typing of intrinsics

Fortran 2018 explicitly permits an ignored type declaration
for the result of a generic intrinsic function.  See the comment
added to Semantics/expression.cpp for an explanation of why this
is somewhat dangerous and worthy of a warning.

Differential Revision: https://reviews.llvm.org/D96879

Added: 
    flang/test/Semantics/badly-typed-intrinsic.f90

Modified: 
    flang/docs/Extensions.md
    flang/include/flang/Evaluate/characteristics.h
    flang/include/flang/Semantics/expression.h
    flang/lib/Evaluate/characteristics.cpp
    flang/lib/Semantics/expression.cpp
    flang/lib/Semantics/resolve-names.cpp
    flang/test/Semantics/symbol18.f90

Removed: 
    


################################################################################
diff  --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md
index 24983456ea0c..9a057104ed6e 100644
--- a/flang/docs/Extensions.md
+++ b/flang/docs/Extensions.md
@@ -205,3 +205,12 @@ accepted if enabled by command-line options.
 * We respect Fortran comments in macro actual arguments (like GNU, Intel, NAG;
   unlike PGI and XLF) on the principle that macro calls should be treated
   like function references.  Fortran's line continuation methods also work.
+
+## Standard features not silently accepted
+
+* Fortran explicitly ignores type declaration statements when they
+  attempt to type the name of a generic intrinsic function (8.2 p3).
+  One can declare `CHARACTER::COS` and still get a real result
+  from `COS(3.14159)`, for example.  f18 will complain when a
+  generic intrinsic function's inferred result type does not
+  match an explicit declaration.  This message is a warning.

diff  --git a/flang/include/flang/Evaluate/characteristics.h b/flang/include/flang/Evaluate/characteristics.h
index 5ca85147ef0c..e9fed59e393a 100644
--- a/flang/include/flang/Evaluate/characteristics.h
+++ b/flang/include/flang/Evaluate/characteristics.h
@@ -154,6 +154,7 @@ class TypeAndShape {
   // called by Fold() to rewrite in place
   TypeAndShape &Rewrite(FoldingContext &);
 
+  std::string AsFortran() const;
   llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
 
 private:

diff  --git a/flang/include/flang/Semantics/expression.h b/flang/include/flang/Semantics/expression.h
index 7b252baa6c7d..f81d5199dc20 100644
--- a/flang/include/flang/Semantics/expression.h
+++ b/flang/include/flang/Semantics/expression.h
@@ -371,7 +371,7 @@ class ExpressionAnalyzer {
   std::optional<CalleeAndArguments> GetCalleeAndArguments(
       const parser::ProcedureDesignator &, ActualArguments &&,
       bool isSubroutine, bool mightBeStructureConstructor = false);
-
+  void CheckBadExplicitType(const SpecificCall &, const Symbol &);
   void CheckForBadRecursion(parser::CharBlock, const semantics::Symbol &);
   bool EnforceTypeConstraint(parser::CharBlock, const MaybeExpr &, TypeCategory,
       bool defaultKind = false);

diff  --git a/flang/lib/Evaluate/characteristics.cpp b/flang/lib/Evaluate/characteristics.cpp
index 6e41aa677570..1e8370928f8a 100644
--- a/flang/lib/Evaluate/characteristics.cpp
+++ b/flang/lib/Evaluate/characteristics.cpp
@@ -155,11 +155,9 @@ bool TypeAndShape::IsCompatibleWith(parser::ContextualMessages &messages,
     bool isElemental, bool thisIsDeferredShape,
     bool thatIsDeferredShape) const {
   if (!type_.IsTkCompatibleWith(that.type_)) {
-    const auto &len{that.LEN()};
     messages.Say(
         "%1$s type '%2$s' is not compatible with %3$s type '%4$s'"_err_en_US,
-        thatIs, that.type_.AsFortran(len ? len->AsFortran() : ""), thisIs,
-        type_.AsFortran(LEN_ ? LEN_->AsFortran() : ""));
+        thatIs, that.AsFortran(), thisIs, AsFortran());
     return false;
   }
   return isElemental ||
@@ -235,6 +233,10 @@ void TypeAndShape::AcquireLEN(const semantics::Symbol &symbol) {
   }
 }
 
+std::string TypeAndShape::AsFortran() const {
+  return type_.AsFortran(LEN_ ? LEN_->AsFortran() : "");
+}
+
 llvm::raw_ostream &TypeAndShape::Dump(llvm::raw_ostream &o) const {
   o << type_.AsFortran(LEN_ ? LEN_->AsFortran() : "");
   attrs_.Dump(o, EnumToString);

diff  --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index c5ca4126f6be..2c4ce6af989b 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -2044,6 +2044,7 @@ auto ExpressionAnalyzer::GetCalleeAndArguments(const parser::Name &name,
     if (std::optional<SpecificCall> specificCall{context_.intrinsics().Probe(
             CallCharacteristics{ultimate.name().ToString(), isSubroutine},
             arguments, GetFoldingContext())}) {
+      CheckBadExplicitType(*specificCall, *symbol);
       return CalleeAndArguments{
           ProcedureDesignator{std::move(specificCall->specificIntrinsic)},
           std::move(specificCall->arguments)};
@@ -2081,6 +2082,39 @@ auto ExpressionAnalyzer::GetCalleeAndArguments(const parser::Name &name,
   return std::nullopt;
 }
 
+// Fortran 2018 expressly states (8.2 p3) that any declared type for a
+// generic intrinsic function "has no effect" on the result type of a
+// call to that intrinsic.  So one can declare "character*8 cos" and
+// still get a real result from "cos(1.)".  This is a dangerous feature,
+// especially since implementations are free to extend their sets of
+// intrinsics, and in doing so might clash with a name in a program.
+// So we emit a warning in this situation, and perhaps it should be an
+// error -- any correctly working program can silence the message by
+// simply deleting the pointless type declaration.
+void ExpressionAnalyzer::CheckBadExplicitType(
+    const SpecificCall &call, const Symbol &intrinsic) {
+  if (intrinsic.GetUltimate().GetType()) {
+    const auto &procedure{call.specificIntrinsic.characteristics.value()};
+    if (const auto &result{procedure.functionResult}) {
+      if (const auto *typeAndShape{result->GetTypeAndShape()}) {
+        if (auto declared{
+                typeAndShape->Characterize(intrinsic, GetFoldingContext())}) {
+          if (!declared->type().IsTkCompatibleWith(typeAndShape->type())) {
+            if (auto *msg{Say(
+                    "The result type '%s' of the intrinsic function '%s' is not the explicit declared type '%s'"_en_US,
+                    typeAndShape->AsFortran(), intrinsic.name(),
+                    declared->AsFortran())}) {
+              msg->Attach(intrinsic.name(),
+                  "Ignored declaration of intrinsic function '%s'"_en_US,
+                  intrinsic.name());
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
 void ExpressionAnalyzer::CheckForBadRecursion(
     parser::CharBlock callSite, const semantics::Symbol &proc) {
   if (const auto *scope{proc.scope()}) {

diff  --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index b87916d39a4c..d1938901e633 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -3488,6 +3488,15 @@ bool DeclarationVisitor::Pre(const parser::IntrinsicStmt &x) {
       Say(symbol.name(),
           "Symbol '%s' cannot have both EXTERNAL and INTRINSIC attributes"_err_en_US,
           symbol.name());
+    } else if (symbol.GetType()) {
+      // These warnings are worded so that they should make sense in either
+      // order.
+      Say(symbol.name(),
+          "Explicit type declaration ignored for intrinsic function '%s'"_en_US,
+          symbol.name())
+          .Attach(name.source,
+              "INTRINSIC statement for explicitly-typed '%s'"_en_US,
+              name.source);
     }
   }
   return false;
@@ -5994,8 +6003,6 @@ void ResolveNamesVisitor::HandleProcedureName(
     bool convertedToProcEntity{ConvertToProcEntity(*symbol)};
     if (convertedToProcEntity && !symbol->attrs().test(Attr::EXTERNAL) &&
         IsIntrinsic(symbol->name(), flag) && !IsDummy(*symbol)) {
-      // 8.2(3): ignore type from intrinsic in type-declaration-stmt
-      symbol->get<ProcEntityDetails>().set_interface(ProcInterface{});
       AcquireIntrinsicProcedureFlags(*symbol);
     }
     if (!SetProcFlag(name, *symbol, flag)) {

diff  --git a/flang/test/Semantics/badly-typed-intrinsic.f90 b/flang/test/Semantics/badly-typed-intrinsic.f90
new file mode 100644
index 000000000000..8f570370e51b
--- /dev/null
+++ b/flang/test/Semantics/badly-typed-intrinsic.f90
@@ -0,0 +1,29 @@
+! RUN: %f18 -fsyntax-only %s 2>&1 | FileCheck %s
+
+type :: t
+end type
+integer :: acos
+double precision :: cos
+!CHECK: Explicit type declaration ignored for intrinsic function 'int'
+complex :: int
+character :: sin
+logical :: asin
+type(t) :: atan
+!CHECK: INTRINSIC statement for explicitly-typed 'int'
+intrinsic int
+!CHECK: The result type 'REAL(4)' of the intrinsic function 'acos' is not the explicit declared type 'INTEGER(4)'
+!CHECK: Ignored declaration of intrinsic function 'acos'
+print *, acos(0.)
+!CHECK: The result type 'REAL(4)' of the intrinsic function 'cos' is not the explicit declared type 'REAL(8)'
+!CHECK: Ignored declaration of intrinsic function 'cos'
+print *, cos(0.)
+!CHECK: The result type 'REAL(4)' of the intrinsic function 'sin' is not the explicit declared type 'CHARACTER(KIND=1,LEN=1_8)'
+!CHECK: Ignored declaration of intrinsic function 'sin'
+print *, sin(0.)
+!CHECK: The result type 'REAL(4)' of the intrinsic function 'asin' is not the explicit declared type 'LOGICAL(4)'
+!CHECK: Ignored declaration of intrinsic function 'asin'
+print *, asin(0.)
+!CHECK: The result type 'REAL(4)' of the intrinsic function 'atan' is not the explicit declared type 't'
+!CHECK: Ignored declaration of intrinsic function 'atan'
+print *, atan(0.)
+end

diff  --git a/flang/test/Semantics/symbol18.f90 b/flang/test/Semantics/symbol18.f90
index a0fa0eb7ff9f..c3197d7ec924 100644
--- a/flang/test/Semantics/symbol18.f90
+++ b/flang/test/Semantics/symbol18.f90
@@ -4,7 +4,7 @@
 
 !DEF: /p1 MainProgram
 program p1
- !DEF: /p1/cos ELEMENTAL, INTRINSIC, PURE (Function) ProcEntity
+ !DEF: /p1/cos ELEMENTAL, INTRINSIC, PURE (Function) ProcEntity INTEGER(4)
  integer cos
  !DEF: /p1/y (Implicit) ObjectEntity REAL(4)
  !REF: /p1/cos


        


More information about the flang-commits mailing list