@@ -1758,10 +1758,27 @@ void OmpVisitor::ProcessReductionSpecifier(
17581758 &MakeSymbol (*name, MiscDetails{MiscDetails::Kind::ConstructName});
17591759 }
17601760 }
1761- // Creating a new scope in case the combiner expression (or clauses) use
1762- // reerved identifiers, like "omp_in". This is a temporary solution until
1763- // we deal with these in a more thorough way.
1761+
17641762 auto &typeList{std::get<parser::OmpTypeNameList>(spec.t )};
1763+
1764+ // Create a temporary variable declaration for the three variables
1765+ // used in the reduction specifier (omp_out, omp_in and omp_priv),
1766+ // with of the type in the typeList.
1767+ //
1768+ // In theory it would be possible to create only variables that are
1769+ // actually used, but that requires walking the entire parse-tree of the
1770+ // expressions, and finding the relevant variables [there may well be other
1771+ // variables involved too].
1772+ //
1773+ // This allows doing semantic analysis where the type is a derived type
1774+ // e.g omp_out%x = omp_out%x + omp_in%x.
1775+ //
1776+ // These need to be temporary (in their own scope). If they are created
1777+ // as variables in the outer scope, if there's more than one type in the
1778+ // typelist, duplicate symbols will be reported.
1779+ const parser::CharBlock ompVarNames[]{
1780+ {" omp_in" , 6 }, {" omp_out" , 7 }, {" omp_priv" , 8 }};
1781+
17651782 for (auto &t : typeList.v ) {
17661783 PushScope (Scope::Kind::OtherConstruct, nullptr );
17671784 BeginDeclTypeSpec ();
@@ -1770,8 +1787,6 @@ void OmpVisitor::ProcessReductionSpecifier(
17701787
17711788 const DeclTypeSpec *typeSpec{GetDeclTypeSpec ()};
17721789 assert (typeSpec && " We should have a type here" );
1773- const parser::CharBlock ompVarNames[]{
1774- {" omp_in" , 6 }, {" omp_out" , 7 }, {" omp_priv" , 8 }};
17751790
17761791 for (auto &nm : ompVarNames) {
17771792 ObjectEntityDetails details{};
0 commit comments