forked from OSchip/llvm-project
[flang] Fix bugs with use-associated derived type with rename
When a derived type is use-associated with a rename, like `use m, only: t2 => t1` we need to record in the `DerivedTypeSpec` both the local-name in this scope and the symbol for the derived type. In most cases we need to work the the type symbol and its `DerivedTypeDetails`, but when writing the type to the module file we need the local-name. The name of the type symbol may be hidden or not use-associated. When analyzing a `parser::Name` we don't want to follow use-associations because we could end up with the wrong name in a `DataRef` (i.e. the use-name rather than the local-name). But that means that `GetNamedConstantValue()` does have to follow them or named constants won't always be folded. Fixes flang-compiler/f18#729. Original-commit: flang-compiler/f18@50d8921c69 Reviewed-on: https://github.com/flang-compiler/f18/pull/740
This commit is contained in:
parent
0b86ab186d
commit
a29678ddb6
|
@ -1184,7 +1184,7 @@ Expr<Type<TypeCategory::Character, KIND>> FoldIntrinsicFunction(
|
|||
template<typename T>
|
||||
std::optional<Expr<T>> GetNamedConstantValue(
|
||||
FoldingContext &context, const Symbol &symbol0) {
|
||||
const Symbol &symbol{ResolveAssociations(symbol0)};
|
||||
const Symbol &symbol{ResolveAssociations(symbol0).GetUltimate()};
|
||||
if (IsNamedConstant(symbol)) {
|
||||
if (const auto *object{
|
||||
symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
|
||||
|
|
|
@ -441,7 +441,7 @@ std::string SomeDerived::AsFortran() const {
|
|||
std::string DerivedTypeSpecAsFortran(const semantics::DerivedTypeSpec &spec) {
|
||||
if (spec.HasActualParameters()) {
|
||||
std::stringstream ss;
|
||||
ss << spec.typeSymbol().name().ToString();
|
||||
ss << spec.name().ToString();
|
||||
char ch{'('};
|
||||
for (const auto &[name, value] : spec.parameters()) {
|
||||
ss << ch << name.ToString() << '=';
|
||||
|
@ -457,7 +457,7 @@ std::string DerivedTypeSpecAsFortran(const semantics::DerivedTypeSpec &spec) {
|
|||
ss << ')';
|
||||
return ss.str();
|
||||
} else {
|
||||
return spec.typeSymbol().name().ToString();
|
||||
return spec.name().ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -601,19 +601,12 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Name &n) {
|
|||
return std::nullopt;
|
||||
} else {
|
||||
const Symbol &ultimate{n.symbol->GetUltimate()};
|
||||
if (ultimate.detailsIf<semantics::TypeParamDetails>()) {
|
||||
if (ultimate.has<semantics::TypeParamDetails>()) {
|
||||
// A bare reference to a derived type parameter (within a parameterized
|
||||
// derived type definition)
|
||||
return AsMaybeExpr(MakeBareTypeParamInquiry(&ultimate));
|
||||
} else {
|
||||
const auto *details{ultimate.detailsIf<semantics::ObjectEntityDetails>()};
|
||||
if (details && semantics::IsNamedConstant(ultimate) && details->type() &&
|
||||
details->type()->AsIntrinsic() && !details->IsArray() &&
|
||||
details->init()) {
|
||||
return details->init();
|
||||
} else {
|
||||
return Designate(DataRef{*n.symbol});
|
||||
}
|
||||
return Designate(DataRef{*n.symbol});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2006,7 +1999,7 @@ static void FixMisparsedFunctionReference(
|
|||
CheckFuncRefToArrayElementRefHasSubscripts(context, funcRef);
|
||||
u = common::Indirection{funcRef.ConvertToArrayElementRef()};
|
||||
} else {
|
||||
common::die("can't fix misparsed function as array reference");
|
||||
DIE("can't fix misparsed function as array reference");
|
||||
}
|
||||
} else if (const auto *name{std::get_if<parser::Name>(&proc.u)}) {
|
||||
// A procedure component reference can't be a structure
|
||||
|
@ -2021,15 +2014,15 @@ static void FixMisparsedFunctionReference(
|
|||
if (derivedType != nullptr) {
|
||||
if constexpr (common::HasMember<parser::StructureConstructor,
|
||||
uType>) {
|
||||
CHECK(derivedType->has<semantics::DerivedTypeDetails>());
|
||||
auto &scope{context.FindScope(name->source)};
|
||||
const semantics::DeclTypeSpec &type{
|
||||
semantics::FindOrInstantiateDerivedType(
|
||||
scope, semantics::DerivedTypeSpec{*derivedType}, context)};
|
||||
semantics::FindOrInstantiateDerivedType(scope,
|
||||
semantics::DerivedTypeSpec{
|
||||
origSymbol->name(), *derivedType},
|
||||
context)};
|
||||
u = funcRef.ConvertToStructureConstructor(type.derivedTypeSpec());
|
||||
} else {
|
||||
common::die(
|
||||
"can't fix misparsed function as structure constructor");
|
||||
DIE("can't fix misparsed function as structure constructor");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,8 +68,8 @@ public:
|
|||
|
||||
SubprogramSymbolCollector(const Symbol &symbol)
|
||||
: symbol_{symbol}, scope_{*symbol.scope()} {}
|
||||
SymbolVector symbols() const { return need_; }
|
||||
SymbolSet imports() const { return imports_; }
|
||||
const SymbolVector &symbols() const { return need_; }
|
||||
const std::set<SourceName> &imports() const { return imports_; }
|
||||
void Collect();
|
||||
|
||||
private:
|
||||
|
@ -79,13 +79,14 @@ private:
|
|||
SymbolVector need_; // symbols that are needed
|
||||
SymbolSet needSet_; // symbols already in need_
|
||||
SymbolSet useSet_; // use-associations that might be needed
|
||||
SymbolSet imports_; // imports from host that are needed
|
||||
std::set<SourceName> imports_; // imports from host that are needed
|
||||
|
||||
void DoSymbol(const Symbol &);
|
||||
void DoSymbol(const SourceName &, const Symbol &);
|
||||
void DoType(const DeclTypeSpec *);
|
||||
void DoBound(const Bound &);
|
||||
void DoParamValue(const ParamValue &);
|
||||
bool NeedImport(const Symbol &);
|
||||
bool NeedImport(const SourceName &, const Symbol &);
|
||||
|
||||
struct SymbolVisitor : public virtual evaluate::VisitorBase<SymbolVector> {
|
||||
using Result = SymbolVector;
|
||||
|
@ -253,7 +254,7 @@ void ModFileWriter::PutDerivedType(const Symbol &typeSymbol) {
|
|||
auto &details{typeSymbol.get<DerivedTypeDetails>()};
|
||||
PutAttrs(decls_ << "type", typeSymbol.attrs());
|
||||
if (const DerivedTypeSpec * extends{typeSymbol.GetParentTypeSpec()}) {
|
||||
decls_ << ",extends(" << extends->typeSymbol().name() << ')';
|
||||
decls_ << ",extends(" << extends->name() << ')';
|
||||
}
|
||||
decls_ << "::" << typeSymbol.name();
|
||||
auto &typeScope{*typeSymbol.scope()};
|
||||
|
@ -329,8 +330,8 @@ void ModFileWriter::PutSubprogram(const Symbol &symbol) {
|
|||
}
|
||||
CHECK(typeBindings.str().empty());
|
||||
os << writer.uses_.str();
|
||||
for (const Symbol *import : collector.imports()) {
|
||||
decls_ << "import::" << import->name().ToString() << "\n";
|
||||
for (const SourceName &import : collector.imports()) {
|
||||
decls_ << "import::" << import << "\n";
|
||||
}
|
||||
os << writer.decls_.str();
|
||||
os << "end\n";
|
||||
|
@ -811,15 +812,20 @@ void SubprogramSymbolCollector::Collect() {
|
|||
}
|
||||
}
|
||||
|
||||
// Do symbols this one depends on; then add to need_
|
||||
void SubprogramSymbolCollector::DoSymbol(const Symbol &symbol) {
|
||||
DoSymbol(symbol.name(), symbol);
|
||||
}
|
||||
|
||||
// Do symbols this one depends on; then add to need_
|
||||
void SubprogramSymbolCollector::DoSymbol(
|
||||
const SourceName &name, const Symbol &symbol) {
|
||||
const auto &scope{symbol.owner()};
|
||||
if (scope != scope_ && !scope.IsDerivedType()) {
|
||||
if (scope != scope_.parent()) {
|
||||
useSet_.insert(&symbol);
|
||||
}
|
||||
if (NeedImport(symbol)) {
|
||||
imports_.insert(&symbol);
|
||||
if (NeedImport(name, symbol)) {
|
||||
imports_.insert(name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -871,7 +877,7 @@ void SubprogramSymbolCollector::DoType(const DeclTypeSpec *type) {
|
|||
if (const DerivedTypeSpec * derived{type->AsDerived()}) {
|
||||
const auto &typeSymbol{derived->typeSymbol()};
|
||||
if (const DerivedTypeSpec * extends{typeSymbol.GetParentTypeSpec()}) {
|
||||
DoSymbol(extends->typeSymbol());
|
||||
DoSymbol(extends->name(), extends->typeSymbol());
|
||||
}
|
||||
for (const auto pair : derived->parameters()) {
|
||||
DoParamValue(pair.second);
|
||||
|
@ -880,7 +886,7 @@ void SubprogramSymbolCollector::DoType(const DeclTypeSpec *type) {
|
|||
const auto &comp{*pair.second};
|
||||
DoSymbol(comp);
|
||||
}
|
||||
DoSymbol(typeSymbol);
|
||||
DoSymbol(derived->name(), derived->typeSymbol());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -897,12 +903,13 @@ void SubprogramSymbolCollector::DoParamValue(const ParamValue ¶mValue) {
|
|||
}
|
||||
|
||||
// Do we need a IMPORT of this symbol into an interface block?
|
||||
bool SubprogramSymbolCollector::NeedImport(const Symbol &symbol) {
|
||||
bool SubprogramSymbolCollector::NeedImport(
|
||||
const SourceName &name, const Symbol &symbol) {
|
||||
if (!isInterface_) {
|
||||
return false;
|
||||
} else if (symbol.owner() != scope_.parent()) {
|
||||
// detect import from parent of use-associated symbol
|
||||
const auto *found{scope_.FindSymbol(symbol.name())};
|
||||
const auto *found{scope_.FindSymbol(name)};
|
||||
return DEREF(found).has<UseDetails>() && found->owner() != scope_;
|
||||
} else {
|
||||
return true;
|
||||
|
|
|
@ -859,7 +859,9 @@ private:
|
|||
Symbol &DeclareUnknownEntity(const parser::Name &, Attrs);
|
||||
Symbol &DeclareProcEntity(const parser::Name &, Attrs, const ProcInterface &);
|
||||
void SetType(const parser::Name &, const DeclTypeSpec &);
|
||||
const Symbol *ResolveDerivedType(const parser::Name &);
|
||||
std::optional<DerivedTypeSpec> ResolveDerivedType(const parser::Name &);
|
||||
std::optional<DerivedTypeSpec> ResolveExtendsType(
|
||||
const parser::Name &, const parser::Name *);
|
||||
Symbol *MakeTypeSymbol(const SourceName &, Details &&);
|
||||
Symbol *MakeTypeSymbol(const parser::Name &, Details &&);
|
||||
bool OkToAddComponent(const parser::Name &, const Symbol * = nullptr);
|
||||
|
@ -3146,10 +3148,11 @@ bool DeclarationVisitor::Pre(const parser::DeclarationTypeSpec::Record &) {
|
|||
|
||||
void DeclarationVisitor::Post(const parser::DerivedTypeSpec &x) {
|
||||
const auto &typeName{std::get<parser::Name>(x.t)};
|
||||
const Symbol *typeSymbol{ResolveDerivedType(typeName)};
|
||||
if (typeSymbol == nullptr) {
|
||||
auto spec{ResolveDerivedType(typeName)};
|
||||
if (!spec) {
|
||||
return;
|
||||
}
|
||||
const Symbol *typeSymbol{&spec->typeSymbol()};
|
||||
|
||||
// This DerivedTypeSpec is created initially as a search key.
|
||||
// If it turns out to have the same name and actual parameter
|
||||
|
@ -3157,7 +3160,6 @@ void DeclarationVisitor::Post(const parser::DerivedTypeSpec &x) {
|
|||
// scope, then we'll use that extant spec; otherwise, when this
|
||||
// spec is distinct from all derived types previously instantiated
|
||||
// in the current scope, this spec will be moved to that collection.
|
||||
DerivedTypeSpec spec{*typeSymbol};
|
||||
|
||||
// The expressions in a derived type specifier whose values define
|
||||
// non-defaulted type parameters are evaluated in the enclosing scope.
|
||||
|
@ -3204,14 +3206,14 @@ void DeclarationVisitor::Post(const parser::DerivedTypeSpec &x) {
|
|||
"Too many type parameters given for derived type '%s'"_err_en_US);
|
||||
break;
|
||||
}
|
||||
if (spec.FindParameter(name)) {
|
||||
if (spec->FindParameter(name)) {
|
||||
Say(typeName.source,
|
||||
"Multiple values given for type parameter '%s'"_err_en_US, name);
|
||||
} else {
|
||||
const auto &value{std::get<parser::TypeParamValue>(typeParamSpec.t)};
|
||||
ParamValue param{GetParamValue(value, attr)}; // folded
|
||||
if (!param.isExplicit() || param.GetExplicit().has_value()) {
|
||||
spec.AddParamValue(name, std::move(param));
|
||||
spec->AddParamValue(name, std::move(param));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3221,7 +3223,7 @@ void DeclarationVisitor::Post(const parser::DerivedTypeSpec &x) {
|
|||
const Scope *typeScope{typeSymbol->scope()};
|
||||
CHECK(typeScope != nullptr);
|
||||
for (const SourceName &name : parameterNames) {
|
||||
if (!spec.FindParameter(name)) {
|
||||
if (!spec->FindParameter(name)) {
|
||||
auto it{std::find_if(parameterDecls.begin(), parameterDecls.end(),
|
||||
[&](const Symbol *symbol) { return symbol->name() == name; })};
|
||||
if (it != parameterDecls.end()) {
|
||||
|
@ -3236,14 +3238,14 @@ void DeclarationVisitor::Post(const parser::DerivedTypeSpec &x) {
|
|||
}
|
||||
|
||||
auto category{GetDeclTypeSpecCategory()};
|
||||
ProcessParameterExpressions(spec, context().foldingContext());
|
||||
ProcessParameterExpressions(*spec, context().foldingContext());
|
||||
if (const DeclTypeSpec *
|
||||
extant{currScope().FindInstantiatedDerivedType(spec, category)}) {
|
||||
extant{currScope().FindInstantiatedDerivedType(*spec, category)}) {
|
||||
// This derived type and parameter expressions (if any) are already present
|
||||
// in this scope.
|
||||
SetDeclTypeSpec(*extant);
|
||||
} else {
|
||||
DeclTypeSpec &type{currScope().MakeDerivedType(category, std::move(spec))};
|
||||
DeclTypeSpec &type{currScope().MakeDerivedType(category, std::move(*spec))};
|
||||
if (parameterNames.empty() || currScope().IsParameterizedDerivedType()) {
|
||||
// The derived type being instantiated is not a parameterized derived
|
||||
// type, or the instantiation is within the definition of a parameterized
|
||||
|
@ -3326,33 +3328,28 @@ void DeclarationVisitor::Post(const parser::DerivedTypeStmt &x) {
|
|||
// Resolve the EXTENDS() clause before creating the derived
|
||||
// type's symbol to foil attempts to recursively extend a type.
|
||||
auto *extendsName{derivedTypeInfo_.extends};
|
||||
const Symbol *extendsType{nullptr};
|
||||
if (extendsName != nullptr) {
|
||||
if (extendsName->source == name.source) {
|
||||
Say(extendsName->source,
|
||||
"Derived type '%s' cannot extend itself"_err_en_US);
|
||||
} else {
|
||||
extendsType = ResolveDerivedType(*extendsName);
|
||||
}
|
||||
}
|
||||
std::optional<DerivedTypeSpec> extendsType{
|
||||
ResolveExtendsType(name, extendsName)};
|
||||
auto &symbol{MakeSymbol(name, GetAttrs(), DerivedTypeDetails{})};
|
||||
symbol.ReplaceName(name.source);
|
||||
derivedTypeInfo_.type = &symbol;
|
||||
PushScope(Scope::Kind::DerivedType, &symbol);
|
||||
if (extendsType != nullptr) {
|
||||
if (extendsType.has_value()) {
|
||||
// Declare the "parent component"; private if the type is
|
||||
// Any symbol stored in the EXTENDS() clause is temporarily
|
||||
// hidden so that a new symbol can be created for the parent
|
||||
// component without producing spurious errors about already
|
||||
// existing.
|
||||
const Symbol &extendsSymbol{extendsType->typeSymbol()};
|
||||
auto restorer{common::ScopedSet(extendsName->symbol, nullptr)};
|
||||
if (OkToAddComponent(*extendsName, extendsType)) {
|
||||
if (OkToAddComponent(*extendsName, &extendsSymbol)) {
|
||||
auto &comp{DeclareEntity<ObjectEntityDetails>(*extendsName, Attrs{})};
|
||||
comp.attrs().set(Attr::PRIVATE, extendsType->attrs().test(Attr::PRIVATE));
|
||||
comp.attrs().set(
|
||||
Attr::PRIVATE, extendsSymbol.attrs().test(Attr::PRIVATE));
|
||||
comp.set(Symbol::Flag::ParentComp);
|
||||
DeclTypeSpec &type{currScope().MakeDerivedType(
|
||||
DeclTypeSpec::TypeDerived, DerivedTypeSpec{*extendsType})};
|
||||
type.derivedTypeSpec().set_scope(*extendsType->scope());
|
||||
DeclTypeSpec::TypeDerived, std::move(*extendsType))};
|
||||
type.derivedTypeSpec().set_scope(*extendsSymbol.scope());
|
||||
comp.SetType(type);
|
||||
DerivedTypeDetails &details{symbol.get<DerivedTypeDetails>()};
|
||||
details.add_component(comp);
|
||||
|
@ -4244,15 +4241,15 @@ void DeclarationVisitor::SetType(
|
|||
}
|
||||
}
|
||||
|
||||
// Find the Symbol for this derived type.
|
||||
const Symbol *DeclarationVisitor::ResolveDerivedType(const parser::Name &name) {
|
||||
std::optional<DerivedTypeSpec> DeclarationVisitor::ResolveDerivedType(
|
||||
const parser::Name &name) {
|
||||
const Symbol *symbol{FindSymbol(name)};
|
||||
if (!symbol) {
|
||||
Say(name, "Derived type '%s' not found"_err_en_US);
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
if (CheckUseError(name)) {
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
symbol = &symbol->GetUltimate();
|
||||
if (auto *details{symbol->detailsIf<GenericDetails>()}) {
|
||||
|
@ -4262,9 +4259,22 @@ const Symbol *DeclarationVisitor::ResolveDerivedType(const parser::Name &name) {
|
|||
}
|
||||
if (!symbol->has<DerivedTypeDetails>()) {
|
||||
Say(name, "'%s' is not a derived type"_err_en_US);
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
return DerivedTypeSpec{name.source, *symbol};
|
||||
}
|
||||
|
||||
std::optional<DerivedTypeSpec> DeclarationVisitor::ResolveExtendsType(
|
||||
const parser::Name &typeName, const parser::Name *extendsName) {
|
||||
if (extendsName == nullptr) {
|
||||
return std::nullopt;
|
||||
} else if (typeName.source == extendsName->source) {
|
||||
Say(extendsName->source,
|
||||
"Derived type '%s' cannot extend itself"_err_en_US);
|
||||
return std::nullopt;
|
||||
} else {
|
||||
return ResolveDerivedType(*extendsName);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
Symbol *DeclarationVisitor::NoteInterfaceName(const parser::Name &name) {
|
||||
|
|
|
@ -22,14 +22,12 @@
|
|||
|
||||
namespace Fortran::semantics {
|
||||
|
||||
DerivedTypeSpec::DerivedTypeSpec(const DerivedTypeSpec &that)
|
||||
: typeSymbol_{that.typeSymbol_}, scope_{that.scope_}, parameters_{
|
||||
that.parameters_} {}
|
||||
|
||||
DerivedTypeSpec::DerivedTypeSpec(DerivedTypeSpec &&that)
|
||||
: typeSymbol_{that.typeSymbol_}, scope_{that.scope_}, parameters_{std::move(
|
||||
that.parameters_)} {
|
||||
DerivedTypeSpec::DerivedTypeSpec(SourceName name, const Symbol &typeSymbol)
|
||||
: name_{name}, typeSymbol_{typeSymbol} {
|
||||
CHECK(typeSymbol.has<DerivedTypeDetails>());
|
||||
}
|
||||
DerivedTypeSpec::DerivedTypeSpec(const DerivedTypeSpec &that) = default;
|
||||
DerivedTypeSpec::DerivedTypeSpec(DerivedTypeSpec &&that) = default;
|
||||
|
||||
void DerivedTypeSpec::set_scope(const Scope &scope) {
|
||||
CHECK(!scope_);
|
||||
|
@ -54,7 +52,7 @@ ParamValue *DerivedTypeSpec::FindParameter(SourceName target) {
|
|||
|
||||
std::string DerivedTypeSpec::AsFortran() const {
|
||||
std::stringstream ss;
|
||||
ss << typeSymbol_.name().ToString();
|
||||
ss << name_;
|
||||
if (!parameters_.empty()) {
|
||||
ss << '(';
|
||||
bool first = true;
|
||||
|
|
|
@ -227,12 +227,15 @@ private:
|
|||
};
|
||||
std::ostream &operator<<(std::ostream &, const ArraySpec &);
|
||||
|
||||
// Each DerivedTypeSpec has a typeSymbol that has DerivedTypeSpec.
|
||||
// The name may not match the symbol's name in case of a USE rename.
|
||||
class DerivedTypeSpec {
|
||||
public:
|
||||
explicit DerivedTypeSpec(const Symbol &symbol) : typeSymbol_{symbol} {}
|
||||
explicit DerivedTypeSpec(SourceName, const Symbol &);
|
||||
DerivedTypeSpec(const DerivedTypeSpec &);
|
||||
DerivedTypeSpec(DerivedTypeSpec &&);
|
||||
|
||||
const SourceName &name() const { return name_; }
|
||||
const Symbol &typeSymbol() const { return typeSymbol_; }
|
||||
const Scope *scope() const { return scope_; }
|
||||
void set_scope(const Scope &);
|
||||
|
@ -258,6 +261,7 @@ public:
|
|||
std::string AsFortran() const;
|
||||
|
||||
private:
|
||||
SourceName name_;
|
||||
const Symbol &typeSymbol_;
|
||||
const Scope *scope_{nullptr}; // same as typeSymbol_.scope() unless PDT
|
||||
std::map<SourceName, ParamValue> parameters_;
|
||||
|
|
|
@ -97,10 +97,78 @@ end
|
|||
! character(l2,4)::x
|
||||
! interface
|
||||
! subroutine s(x,y)
|
||||
! import::l2
|
||||
! import::f2
|
||||
! import::l2
|
||||
! character(l2,4)::x
|
||||
! character(f2(l2),1)::y
|
||||
! end
|
||||
! end interface
|
||||
!end
|
||||
|
||||
module m6a
|
||||
type t1
|
||||
end type
|
||||
end
|
||||
!Expect: m6a.mod
|
||||
!module m6a
|
||||
! type::t1
|
||||
! end type
|
||||
!end
|
||||
|
||||
module m6b
|
||||
use m6a, only: t2 => t1
|
||||
contains
|
||||
subroutine s(x)
|
||||
type(t2) :: x
|
||||
end
|
||||
end
|
||||
!Expect: m6b.mod
|
||||
!module m6b
|
||||
! use m6a,only:t2=>t1
|
||||
!contains
|
||||
! subroutine s(x)
|
||||
! type(t2)::x
|
||||
! end
|
||||
!end
|
||||
|
||||
module m6c
|
||||
use m6a, only: t2 => t1
|
||||
type, extends(t2) :: t
|
||||
end type
|
||||
end
|
||||
!Expect: m6c.mod
|
||||
!module m6c
|
||||
! use m6a,only:t2=>t1
|
||||
! type,extends(t2)::t
|
||||
! end type
|
||||
!end
|
||||
|
||||
module m6d
|
||||
use m6a, only: t2 => t1
|
||||
type(t2), parameter :: p = t2()
|
||||
end
|
||||
!Expect: m6d.mod
|
||||
!module m6d
|
||||
! use m6a,only:t2=>t1
|
||||
! type(t2),parameter::p=t2()
|
||||
!end
|
||||
|
||||
module m6e
|
||||
use m6a, only: t2 => t1
|
||||
interface
|
||||
subroutine s(x)
|
||||
import t2
|
||||
type(t2) :: x
|
||||
end subroutine
|
||||
end interface
|
||||
end
|
||||
!Expect: m6e.mod
|
||||
!module m6e
|
||||
! use m6a,only:t2=>t1
|
||||
! interface
|
||||
! subroutine s(x)
|
||||
! import::t2
|
||||
! type(t2)::x
|
||||
! end
|
||||
! end interface
|
||||
!end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
! Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||
! Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
!
|
||||
! Licensed under the Apache License, Version 2.0 (the "License");
|
||||
! you may not use this file except in compliance with the License.
|
||||
|
@ -97,7 +97,7 @@ subroutine s1
|
|||
i = x%t1
|
||||
!REF: /s1/i
|
||||
!REF: /s1/x
|
||||
!DEF: /s1/t3/t2 (ParentComp) ObjectEntity TYPE(t1)
|
||||
!DEF: /s1/t3/t2 (ParentComp) ObjectEntity TYPE(t2)
|
||||
!REF: /m1/t1/t1
|
||||
i = x%t2%t1
|
||||
end subroutine
|
||||
|
|
Loading…
Reference in New Issue