Changeset 81e768d for src/Validate


Ignore:
Timestamp:
Nov 28, 2024, 4:34:08 PM (8 weeks ago)
Author:
Michael Brooks <mlbrooks@…>
Branches:
master
Children:
46c4dea
Parents:
f5e37a4
Message:

Fix #276; add support for c-array parameters using dependent lengths.

Without this fix, declarations like

void f( int m, int n, float[m][n] );

would either

  • generate bad C code, with unmangled variable names appearing in the function definition, or
  • refuse to resolve a valid-c call of such a function.

tests/array-collections/c-dependent: add direct tests of such cases
tests/tuplearray: activate and expand cases which were blocked on #276
tests/array: activate case fm5y, which was blocked on #276; [noise] adjust source line numbers in .expect
tests/typedefRedef: expand coverage of "error, an array detail is different" cases; [noise] adjust source line numbers in .expect
tests/functions: [noise] adjust .expect to have resolved array sizes (extra casts) in the diffed code dump

The fix is:

  • (ResolvExpr/ResolveTypeof?, ResolvExpr/Resolver?) Resolve the dimension expressions, where they were missed.
  • (ResolvExpr/Resolver?) Prevent dimension expressions that are bound to other parameters from escaping in the function's type, to where they are out of scope. In the f example above, redact the type shown to callers from void (*)(int, int, float[m][n]) to void (*)(int, int, float[][*]).
  • (ResolvExpr/Unify?) Relax the matching rules for such a type, when used at a call site, letting the patameters wildcard type match with the concrete type in scope at the caller's side.
  • (Validate/ReplaceTypedef?) Apply the former, stricter matching rules to the one place where they are still needed: detecting inconsistent typedefs.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Validate/ReplaceTypedef.cpp

    rf5e37a4 r81e768d  
    120120        }
    121121}
    122 
    123122struct VarLenChecker : public ast::WithShortCircuiting {
    124123        bool result = false;
     
    126125        void previsit( ast::ArrayType const * at ) { result |= at->isVarLen; }
    127126};
    128 
     127static bool hasVarLen( const ast::Type * t ) {
     128        return ast::Pass<VarLenChecker>::read( t );
     129}
     130struct ArrayTypeExtractor {
     131        std::vector<const ast::ArrayType *> result;
     132        void postvisit( const ast::ArrayType * at ) {
     133                result.push_back( at );
     134        }
     135};
     136static bool dimensionPresenceMismatched( const ast::Type * t0, const ast::Type * t1) {
     137        std::vector<const ast::ArrayType *> at0s = std::move(
     138                ast::Pass<ArrayTypeExtractor>::read( t0 ) );
     139        std::vector<const ast::ArrayType *> at1s = std::move(
     140                ast::Pass<ArrayTypeExtractor>::read( t1 ) );
     141        assert( at0s.size() == at1s.size() );
     142        for (size_t i = 0; i < at0s.size(); i++) {
     143                const ast::ArrayType * at0 = at0s[i];
     144                const ast::ArrayType * at1 = at1s[i];
     145                assert( ResolvExpr::typesCompatible( at0, at1 ) );
     146                if ( (at0->dimension != nullptr) != (at1->dimension != nullptr) ) return true;
     147        }
     148        return false;
     149}
    129150ast::Decl const * ReplaceTypedefCore::postvisit(
    130151                ast::TypedefDecl const * decl ) {
     
    133154                ast::Type const * t0 = decl->base;
    134155                ast::Type const * t1 = typedefNames[ decl->name ].first->base;
     156                // [hasVarLen]
    135157                // Cannot redefine VLA typedefs. Note: this is slightly incorrect,
    136158                // because our notion of VLAs at this point in the translator is
     
    139161                // constant/enumerator. The effort required to fix this corner case
    140162                // likely outweighs the utility of allowing it.
     163                // [dimensionPresenceMismatched]
     164                // Core typesCompatible logic interprets absent dimensions as wildcards,
     165                // i.e. float[][*] matches float[][42].
     166                // For detecting incompatible typedefs, we have to interpret them verbatim,
     167                // i.e. float[] is different than float[42].
     168                // But typesCompatible does assure that the pair of types is structurally
     169                // consistent, outside of the dimension expressions.  This assurance guards
     170                // the dimension-presence traversal.  So this traversal logic can (and does)
     171                // assume that ArrayTypes will be encountered in analogous places.
    141172                if ( !ResolvExpr::typesCompatible( t0, t1 )
    142                                 || ast::Pass<VarLenChecker>::read( t0 )
    143                                 || ast::Pass<VarLenChecker>::read( t1 ) ) {
     173                                || hasVarLen( t0 )
     174                                || hasVarLen( t1 )
     175                                || dimensionPresenceMismatched( t0, t1 ) ) {
    144176                        SemanticError( decl->location, "Cannot redefine typedef %s", decl->name.c_str() );
    145177                }
Note: See TracChangeset for help on using the changeset viewer.