Changeset e5628db


Ignore:
Timestamp:
May 12, 2022, 3:10:58 PM (19 months ago)
Author:
caparsons <caparson@…>
Branches:
ADT, ast-experimental, master, pthread-emulation, qualifiedEnum
Children:
8060b2b, f835806
Parents:
f75e25b (diff), 491bb81 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Files:
32 edited

Legend:

Unmodified
Added
Removed
  • benchmark/process-mutilate.py

    rf75e25b re5628db  
    3232
    3333        try:
    34                 latAvs = fields[6]
     34                latAvs = fields[1]
    3535                lat50s = fields[6]
    3636                lat99s = fields[9]
     
    4545                raise Warning("Warning: \"{}\" \"{}\"! can't convert to float".format(lat50s, lat99s))
    4646
    47         return lat50, lat99
     47        return latAv, lat50, lat99
    4848
    4949def want0(line):
  • benchmark/readyQ/bench.go

    rf75e25b re5628db  
    7171                duration = 5
    7272                clock_mode = true
    73                 fmt.Printf("Running for %f seconds\n", duration)
     73                fmt.Printf("Running for %f seconds (default)\n", duration)
    7474        }
    7575
  • benchmark/readyQ/churn.cpp

    rf75e25b re5628db  
    5454                        Fibre * threads[nthreads];
    5555                        for(unsigned i = 0; i < nthreads; i++) {
    56                                 threads[i] = new Fibre( reinterpret_cast<void (*)(void *)>(churner_main), &thddata[i] );
     56                                threads[i] = new Fibre();
     57                                threads[i]->run(churner_main, &thddata[i]);
    5758                        }
    5859                        printf("Starting\n");
  • benchmark/readyQ/cycle.cpp

    rf75e25b re5628db  
    4646                        }
    4747                        for(unsigned i = 0; i < tthreads; i++) {
    48                                 threads[i] = new Fibre( reinterpret_cast<void (*)(void *)>(partner_main), &thddata[i] );
     48                                threads[i] = new Fibre();
     49                                threads[i]->run( partner_main, &thddata[i] );
    4950                        }
    5051                        printf("Starting\n");
  • benchmark/readyQ/rq_bench.hpp

    rf75e25b re5628db  
    143143        }
    144144
     145        if(strcmp(arg, "Y") == 0) {
     146                value = true;
     147                return true;
     148        }
     149
     150        if(strcmp(arg, "y") == 0) {
     151                value = true;
     152                return true;
     153        }
     154
    145155        if(strcmp(arg, "no") == 0) {
     156                value = false;
     157                return true;
     158        }
     159
     160        if(strcmp(arg, "N") == 0) {
     161                value = false;
     162                return true;
     163        }
     164
     165        if(strcmp(arg, "n") == 0) {
    146166                value = false;
    147167                return true;
  • benchmark/readyQ/transfer.cfa

    rf75e25b re5628db  
    1414
    1515bool exhaust = false;
     16volatile bool estop = false;
     17
    1618
    1719thread$ * the_main;
     
    3537static void waitgroup() {
    3638        Time start = timeHiRes();
    37         for(i; nthreads) {
     39        OUTER: for(i; nthreads) {
    3840                PRINT( sout | "Waiting for :" | i | "(" | threads[i]->idx | ")"; )
    3941                while( threads[i]->idx != lead_idx ) {
     
    4244                                print_stats_now( bench_cluster, CFA_STATS_READY_Q | CFA_STATS_IO );
    4345                                serr | "Programs has been blocked for more than 5 secs";
    44                                 exit(1);
     46                                estop = true;
     47                                unpark( the_main );
     48                                break OUTER;
    4549                        }
    4650                }
     
    5963static void lead(MyThread & this) {
    6064        this.idx = ++lead_idx;
    61         if(lead_idx > stop_count) {
     65        if(lead_idx > stop_count || estop) {
    6266                PRINT( sout | "Leader" | this.id | "done"; )
    6367                unpark( the_main );
     
    100104                        wait( this );
    101105                }
    102                 if(lead_idx > stop_count) break;
     106                if(lead_idx > stop_count || estop) break;
    103107        }
    104108}
     
    172176        sout | "Number of processors    : " | nprocs;
    173177        sout | "Number of threads       : " | nthreads;
    174         sout | "Total Operations(ops)   : " | stop_count;
     178        sout | "Total Operations(ops)   : " | lead_idx - 1;
    175179        sout | "Threads parking on wait : " | (exhaust ? "yes" : "no");
    176180        sout | "Rechecking              : " | rechecks;
     181        sout | "ns per transfer         : " | (end - start)`dms / lead_idx;
    177182
    178183
  • benchmark/readyQ/transfer.cpp

    rf75e25b re5628db  
    1212
    1313bool exhaust = false;
     14volatile bool estop = false;
    1415
    1516bench_sem the_main;
     
    4243                                if( to_miliseconds(timeHiRes() - start) > 5'000 ) {
    4344                                        std::cerr << "Programs has been blocked for more than 5 secs" << std::endl;
    44                                         std::exit(1);
     45                                        estop = true;
     46                                        the_main.post();
     47                                        goto END;
    4548                                }
    4649                        }
    4750                }
     51                END:;
    4852                PRINT( std::cout | "Waiting done"; )
    4953        }
     
    5963        void lead() {
    6064                this->idx = ++lead_idx;
    61                 if(lead_idx > stop_count) {
     65                if(lead_idx > stop_count || estop) {
    6266                        PRINT( std::cout << "Leader " << this->id << " done" << std::endl; )
    6367                        the_main.post();
     
    8892        }
    8993
    90         static void main(void * arg) {
    91                 MyThread & self = *reinterpret_cast<MyThread*>(arg);
     94        static void main(MyThread * arg) {
     95                MyThread & self = *arg;
    9296                self.park();
    9397
     
    101105                                self.wait();
    102106                        }
    103                         if(lead_idx > stop_count) break;
     107                        if(lead_idx > stop_count || estop) break;
    104108                }
    105109        }
     
    144148                        for(size_t i = 0; i < nthreads; i++) {
    145149                                threads[i] = new MyThread( i );
    146                                 handles[i] = new Fibre( MyThread::main, threads[i] );
     150                                handles[i] = new Fibre();
     151                                handles[i]->run( MyThread::main, threads[i] );
    147152                        }
    148153
     
    164169                                PRINT( std::cout << i << " joined" << std::endl; )
    165170                                rechecks += thrd.rechecks;
    166                                 // delete( handles[i] );
    167171                                delete( threads[i] );
    168172                        }
     
    176180        std::cout << "Number of processors    : " << nprocs << std::endl;
    177181        std::cout << "Number of threads       : " << nthreads << std::endl;
    178         std::cout << "Total Operations(ops)   : " << stop_count << std::endl;
     182        std::cout << "Total Operations(ops)   : " << (lead_idx - 1) << std::endl;
    179183        std::cout << "Threads parking on wait : " << (exhaust ? "yes" : "no") << std::endl;
    180184        std::cout << "Rechecking              : " << rechecks << std::endl;
     185        std::cout << "ns per transfer         : " << std::fixed << (((double)(end - start)) / (lead_idx)) << std::endl;
    181186
    182187
  • benchmark/readyQ/transfer.go

    rf75e25b re5628db  
    66        "math/rand"
    77        "os"
     8        "regexp"
    89        "runtime"
    910        "sync/atomic"
     
    1617        id uint64
    1718        idx uint64
     19        estop uint64
    1820        seed uint64
    1921}
     
    3436
    3537func NewLeader(size uint64) (*LeaderInfo) {
    36         this := &LeaderInfo{0, 0, uint64(os.Getpid())}
     38        this := &LeaderInfo{0, 0, 0, uint64(os.Getpid())}
    3739
    3840        r := rand.Intn(10)
     
    5153}
    5254
    53 func waitgroup(idx uint64, threads [] MyThread) {
     55func waitgroup(leader * LeaderInfo, idx uint64, threads [] MyThread, main_sem chan struct {}) {
    5456        start := time.Now()
     57        Outer:
    5558        for i := 0; i < len(threads); i++ {
    5659                // fmt.Fprintf(os.Stderr, "Waiting for :%d (%d)\n", threads[i].id, atomic.LoadUint64(&threads[i].idx) );
     
    6164                        if delta.Seconds() > 5 {
    6265                                fmt.Fprintf(os.Stderr, "Programs has been blocked for more than 5 secs")
    63                                 os.Exit(1)
     66                                atomic.StoreUint64(&leader.estop, 1);
     67                                main_sem <- (struct {}{})
     68                                break Outer
    6469                        }
    6570                }
     
    7479                if i != me {
    7580                        // debug!( "Leader waking {}", i);
     81                        defer func() {
     82                                if err := recover(); err != nil {
     83                                        fmt.Fprintf(os.Stderr, "Panic occurred: %s\n", err)
     84                                }
     85                        }()
    7686                        threads[i].sem <- (struct {}{})
    7787                }
     
    8494        atomic.StoreUint64(&leader.idx, nidx);
    8595
    86         if nidx > stop_count {
     96        if nidx > stop_count || atomic.LoadUint64(&leader.estop) != 0 {
    8797                // debug!( "Leader {} done", this.id);
    8898                main_sem <- (struct {}{})
     
    92102        // debug!( "====================\nLeader no {} : {}", nidx, this.id);
    93103
    94         waitgroup(nidx, threads);
     104        waitgroup(leader, nidx, threads, main_sem);
    95105
    96106        leader.next( uint64(len(threads)) );
     
    146156                        waitleader( exhaust, leader, &threads[me], &r )
    147157                }
    148                 if atomic.LoadUint64(&leader.idx) > stop_count { break; }
     158                if atomic.LoadUint64(&leader.idx) > stop_count || atomic.LoadUint64(&leader.estop) != 0 { break; }
    149159        }
    150160
     
    155165func main() {
    156166        // Benchmark specific command line arguments
    157         exhaustOpt := flag.Bool("e", false, "Whether or not threads that have seen the new epoch should park instead of yielding.")
     167        exhaustOpt := flag.String("e", "no", "Whether or not threads that have seen the new epoch should park instead of yielding.")
    158168
    159169        // General benchmark initialization and deinitialization
    160         defer bench_init()()
    161 
    162         exhaust := *exhaustOpt;
     170        bench_init()
     171
     172        exhaustVal := *exhaustOpt;
     173
     174        var exhaust bool
     175        re_yes := regexp.MustCompile("[Yy]|[Yy][Ee][Ss]")
     176        re_no  := regexp.MustCompile("[Nn]|[Nn][Oo]")
     177        if re_yes.Match([]byte(exhaustVal)) {
     178                exhaust = true
     179        } else if re_no.Match([]byte(exhaustVal)) {
     180                exhaust = false
     181        } else {
     182                fmt.Fprintf(os.Stderr, "Unrecognized exhaust(-e) option '%s'\n", exhaustVal)
     183                os.Exit(1)
     184        }
     185
    163186        if clock_mode {
    164                 fmt.Fprintf(os.Stderr, "Programs does not support fixed duration mode")
     187                fmt.Fprintf(os.Stderr, "Programs does not support fixed duration mode\n")
    165188                os.Exit(1)
    166189        }
     
    215238                ws = "no"
    216239        }
    217         p.Printf("Duration (ms)           : %f\n", delta.Milliseconds() )
     240        p.Printf("Duration (ms)           : %d\n", delta.Milliseconds() )
    218241        p.Printf("Number of processors    : %d\n", nprocs )
    219242        p.Printf("Number of threads       : %d\n", nthreads )
    220         p.Printf("Total Operations(ops)   : %15d\n", stop_count )
     243        p.Printf("Total Operations(ops)   : %15d\n", (leader.idx - 1) )
    221244        p.Printf("Threads parking on wait : %s\n", ws)
    222245        p.Printf("Rechecking              : %d\n", rechecks )
    223 }
     246        p.Printf("ns per transfer         : %f\n", float64(delta.Nanoseconds()) / float64(leader.idx) )
     247}
  • benchmark/readyQ/transfer.rs

    rf75e25b re5628db  
    66use std::hint;
    77use std::sync::Arc;
    8 use std::sync::atomic::{AtomicUsize, Ordering};
     8use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
    99use std::time::{Instant,Duration};
    1010
     
    4444                        match val {
    4545                                "yes" => true,
     46                                "Y" => true,
     47                                "y" => true,
    4648                                "no"  => false,
     49                                "N"  => false,
     50                                "n"  => false,
    4751                                "maybe" | "I don't know" | "Can you repeat the question?" => {
    4852                                        eprintln!("Lines for 'Malcolm in the Middle' are not acceptable values of parameter 'exhaust'");
     
    6468        id: AtomicUsize,
    6569        idx: AtomicUsize,
     70        estop: AtomicBool,
    6671        seed: u128,
    6772}
     
    7277                        id: AtomicUsize::new(nthreads),
    7378                        idx: AtomicUsize::new(0),
     79                        estop: AtomicBool::new(false),
    7480                        seed: process::id() as u128
    7581                };
     
    100106}
    101107
    102 fn waitgroup(idx: usize, threads: &Vec<Arc<MyThread>>) {
     108fn waitgroup(leader: &LeaderInfo, idx: usize, threads: &Vec<Arc<MyThread>>, main_sem: &sync::Semaphore) {
    103109        let start = Instant::now();
    104         for t in threads {
     110        'outer: for t in threads {
    105111                debug!( "Waiting for :{} ({})", t.id, t.idx.load(Ordering::Relaxed) );
    106112                while t.idx.load(Ordering::Relaxed) != idx {
     
    108114                        if start.elapsed() > Duration::from_secs(5) {
    109115                                eprintln!("Programs has been blocked for more than 5 secs");
    110                                 std::process::exit(1);
     116                                leader.estop.store(true, Ordering::Relaxed);
     117                                main_sem.add_permits(1);
     118                                break 'outer;
    111119                        }
    112120                }
     
    131139        leader.idx.store(nidx, Ordering::Relaxed);
    132140
    133         if nidx as u64 > exp.stop_count {
     141        if nidx as u64 > exp.stop_count || leader.estop.load(Ordering::Relaxed) {
    134142                debug!( "Leader {} done", this.id);
    135143                main_sem.add_permits(1);
     
    139147        debug!( "====================\nLeader no {} : {}", nidx, this.id);
    140148
    141         waitgroup(nidx, threads);
     149        waitgroup(leader, nidx, threads, main_sem);
    142150
    143151        leader.next( threads.len() );
     
    192200                        wait( exhaust, &leader, &threads[me], &mut rechecks ).await;
    193201                }
    194                 if leader.idx.load(Ordering::Relaxed) as u64 > exp.stop_count { break; }
     202                if leader.idx.load(Ordering::Relaxed) as u64 > exp.stop_count || leader.estop.load(Ordering::Relaxed) { break; }
    195203        }
    196204
     
    273281        println!("Number of processors    : {}", (nprocs).to_formatted_string(&Locale::en));
    274282        println!("Number of threads       : {}", (nthreads).to_formatted_string(&Locale::en));
    275         println!("Total Operations(ops)   : {:>15}", (exp.stop_count).to_formatted_string(&Locale::en));
     283        println!("Total Operations(ops)   : {:>15}", (leader.idx.load(Ordering::Relaxed) - 1).to_formatted_string(&Locale::en));
    276284        println!("Threads parking on wait : {}", if exhaust { "yes" } else { "no" });
    277285        println!("Rechecking              : {}", rechecks );
    278 }
     286        println!("ns per transfer         : {}", ((duration.as_nanos() as f64) / leader.idx.load(Ordering::Relaxed) as f64));
     287
     288}
  • benchmark/readyQ/yield.cpp

    rf75e25b re5628db  
    1010        unsigned long long count = 0;
    1111        for(;;) {
    12                 Fibre::forceYield();
     12                Fibre::yield();
    1313                count++;
    1414                if( clock_mode && stop) break;
     
    3535                        Fibre * threads[nthreads];
    3636                        for(unsigned i = 0; i < nthreads; i++) {
    37                                 threads[i] = new Fibre( reinterpret_cast<void (*)(void *)>(fibre_main), nullptr );
     37                                threads[i] = new Fibre();
     38                                threads[i]->run(fibre_main);
    3839                        }
    3940                        printf("Starting\n");
  • benchmark/rmit.py

    rf75e25b re5628db  
    4646                pass
    4747
    48         if re.search("^[0-9-,]+$", values):
     48        if values.startswith('\\'):
     49                return key, values[1:].split(',')
     50        elif re.search("^[0-9-,]+$", values):
    4951                values = parse_range(values)
    5052                return key, [v for v in values]
  • libcfa/src/concurrency/io.cfa

    rf75e25b re5628db  
    244244
    245245                                        remote = true;
    246                                         __STATS__( false, io.calls.helped++; )
     246                                        __STATS__( true, io.calls.helped++; )
    247247                                }
    248248                                proc->io.target = MAX;
  • libcfa/src/concurrency/ready_subqueue.hfa

    rf75e25b re5628db  
    8383        /* paranoid */ verify( node->link.ts   != 0  );
    8484        /* paranoid */ verify( this.anchor.ts  != 0  );
     85        /* paranoid */ verify( (this.anchor.ts  == MAX) == is_empty );
    8586        return [node, this.anchor.ts];
    8687}
     
    9394// Return the timestamp
    9495static inline unsigned long long ts(__intrusive_lane_t & this) {
    95         // Cannot verify here since it may not be locked
     96        // Cannot verify 'emptiness' here since it may not be locked
    9697        /* paranoid */ verify(this.anchor.ts != 0);
    9798        return this.anchor.ts;
  • libcfa/src/parseargs.cfa

    rf75e25b re5628db  
    208208        }
    209209
     210        if(strcmp(arg, "Y") == 0) {
     211                value = true;
     212                return true;
     213        }
     214
     215        if(strcmp(arg, "y") == 0) {
     216                value = true;
     217                return true;
     218        }
     219
    210220        if(strcmp(arg, "no") == 0) {
     221                value = false;
     222                return true;
     223        }
     224
     225        if(strcmp(arg, "N") == 0) {
     226                value = false;
     227                return true;
     228        }
     229
     230        if(strcmp(arg, "n") == 0) {
    211231                value = false;
    212232                return true;
  • src/AST/Convert.cpp

    rf75e25b re5628db  
    9393        };
    9494
    95     template<typename T>
    96     Getter<T> get() {
    97         return Getter<T>{ *this };
    98     }
     95        template<typename T>
     96        Getter<T> get() {
     97                return Getter<T>{ *this };
     98        }
    9999
    100100        Label makeLabel(Statement * labelled, const ast::Label& label) {
     
    16511651                        // GET_ACCEPT_1(type, FunctionType),
    16521652                        std::move(forall),
     1653                        std::move(assertions),
    16531654                        std::move(paramVars),
    16541655                        std::move(returnVars),
     
    16641665                cache.emplace( old, decl );
    16651666
    1666                 decl->assertions = std::move(assertions);
    16671667                decl->withExprs = GET_ACCEPT_V(withExprs, Expr);
    16681668                decl->stmts = GET_ACCEPT_1(statements, CompoundStmt);
  • src/AST/Copy.cpp

    rf75e25b re5628db  
    1010// Created On       : Thr Nov 11  9:16:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Nov 11  9:28:00 2021
    13 // Update Count     : 0
     12// Last Modified On : Tue May  3 16:28:00 2022
     13// Update Count     : 1
    1414//
    1515
     
    7777        }
    7878
     79        void postvisit( const UniqueExpr * node ) {
     80                readonlyInsert( &node->object );
     81        }
     82
    7983        void postvisit( const MemberExpr * node ) {
    8084                readonlyInsert( &node->member );
  • src/AST/Decl.cpp

    rf75e25b re5628db  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu May 9 10:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Jan 12 16:54:55 2021
    13 // Update Count     : 23
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu May  5 12:10:00 2022
     13// Update Count     : 24
    1414//
    1515
     
    5353// --- FunctionDecl
    5454
    55 FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name, 
     55FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name,
    5656        std::vector<ptr<TypeDecl>>&& forall,
    5757        std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
     
    7474        }
    7575        this->type = ftype;
     76}
     77
     78FunctionDecl::FunctionDecl( const CodeLocation & location, const std::string & name,
     79        std::vector<ptr<TypeDecl>>&& forall, std::vector<ptr<DeclWithType>>&& assertions,
     80        std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
     81        CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
     82        std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
     83: DeclWithType( location, name, storage, linkage, std::move(attrs), fs ),
     84                params( std::move(params) ), returns( std::move(returns) ),
     85                type_params( std::move( forall) ), assertions( std::move( assertions ) ),
     86                type( nullptr ), stmts( stmts ) {
     87        FunctionType * type = new FunctionType( (isVarArgs) ? VariableArgs : FixedArgs );
     88        for ( auto & param : this->params ) {
     89                type->params.emplace_back( param->get_type() );
     90        }
     91        for ( auto & ret : this->returns ) {
     92                type->returns.emplace_back( ret->get_type() );
     93        }
     94        for ( auto & param : this->type_params ) {
     95                type->forall.emplace_back( new TypeInstType( param ) );
     96        }
     97        for ( auto & assertion : this->assertions ) {
     98                type->assertions.emplace_back(
     99                        new VariableExpr( assertion->location, assertion ) );
     100        }
     101        this->type = type;
    76102}
    77103
  • src/AST/Decl.hpp

    rf75e25b re5628db  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu May 9 10:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 12 18:25:05 2021
    13 // Update Count     : 32
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu May  5 12:09:00 2022
     13// Update Count     : 33
    1414//
    1515
     
    135135        std::vector< ptr<Expr> > withExprs;
    136136
     137        // The difference between the two constructors is in how they handle
     138        // assertions. The first constructor uses the assertions from the type
     139        // parameters, in the style of the old ast, and puts them on the type.
     140        // The second takes an explicite list of assertions and builds a list of
     141        // references to them on the type.
     142
    137143        FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall,
    138144                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    139145                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C,
    140146                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
    141         // : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),
    142         //  stmts( stmts ) {}
     147
     148        FunctionDecl( const CodeLocation & location, const std::string & name,
     149                std::vector<ptr<TypeDecl>>&& forall, std::vector<ptr<DeclWithType>>&& assertions,
     150                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
     151                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C,
     152                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
    143153
    144154        const Type * get_type() const override;
  • src/AST/Expr.hpp

    rf75e25b re5628db  
    784784public:
    785785        ptr<Expr> expr;
    786         ptr<ObjectDecl> object;
     786        readonly<ObjectDecl> object;
    787787        ptr<VariableExpr> var;
    788788        unsigned long long id;
  • src/AST/Label.hpp

    rf75e25b re5628db  
    3434        std::vector< ptr<Attribute> > attributes;
    3535
    36         Label( CodeLocation loc, const std::string& name = "",
     36        Label( const CodeLocation& loc, const std::string& name = "",
    3737                std::vector<ptr<Attribute>> && attrs = std::vector<ptr<Attribute>>{} )
    3838        : location( loc ), name( name ), attributes( attrs ) {}
  • src/AST/Node.hpp

    rf75e25b re5628db  
    1010// Created On       : Wed May 8 10:27:04 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Mar 25 10:33:00 2022
    13 // Update Count     : 7
     12// Last Modified On : Mon May  9 10:20:00 2022
     13// Update Count     : 8
    1414//
    1515
     
    4949
    5050        bool unique() const { return strong_count == 1; }
    51         bool isManaged() const {return strong_count > 0; }
     51        bool isManaged() const { return strong_count > 0; }
     52        bool isReferenced() const { return weak_count > 0; }
     53        bool isStable() const {
     54                return (1 == strong_count || (1 < strong_count && 0 == weak_count));
     55        }
    5256
    5357private:
  • src/AST/Pass.proto.hpp

    rf75e25b re5628db  
    131131        template< typename node_t >
    132132        struct result1 {
    133                 bool differs;
    134                 const node_t * value;
     133                bool differs = false;
     134                const node_t * value = nullptr;
    135135
    136136                template< typename object_t, typename super_t, typename field_t >
     
    151151                };
    152152
    153                 bool differs;
     153                bool differs = false;
    154154                container_t< delta > values;
    155155
     
    167167        template< template<class...> class container_t, typename node_t >
    168168        struct resultN {
    169                 bool differs;
     169                bool differs = false;
    170170                container_t<ptr<node_t>> values;
    171171
  • src/AST/Stmt.cpp

    rf75e25b re5628db  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed May  8 13:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb  2 19:01:20 2022
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue May  3 15:18:20 2022
     13// Update Count     : 4
    1414//
    1515
    1616#include "Stmt.hpp"
    1717
    18 
     18#include "Copy.hpp"
    1919#include "DeclReplacer.hpp"
    2020#include "Type.hpp"
     
    2323
    2424// --- CompoundStmt
    25 CompoundStmt::CompoundStmt( const CompoundStmt& other ) : Stmt(other), kids(other.kids) {
     25CompoundStmt::CompoundStmt( const CompoundStmt& other ) : Stmt(other), kids() {
     26        // Statements can have weak references to them, if that happens inserting
     27        // the original node into the new list will put the original node in a
     28        // bad state, where it cannot be mutated. To avoid this, just perform an
     29        // additional shallow copy on the statement.
     30        for ( const Stmt * kid : other.kids ) {
     31                if ( kid->isReferenced() ) {
     32                        kids.emplace_back( ast::shallowCopy( kid ) );
     33                } else {
     34                        kids.emplace_back( kid );
     35                }
     36        }
     37
    2638        // when cloning a compound statement, we may end up cloning declarations which
    2739        // are referred to by VariableExprs throughout the block. Cloning a VariableExpr
  • src/AST/Stmt.hpp

    rf75e25b re5628db  
    5858        // cannot be, they are sub-types of this type, for organization.
    5959
    60     StmtClause( const CodeLocation & loc )
     60        StmtClause( const CodeLocation & loc )
    6161                : ParseNode(loc) {}
    6262
     
    396396class WaitForClause final : public StmtClause {
    397397  public:
    398     ptr<Expr> target_func;
    399     std::vector<ptr<Expr>> target_args;
    400     ptr<Stmt> stmt;
    401     ptr<Expr> cond;
    402 
    403     WaitForClause( const CodeLocation & loc )
     398        ptr<Expr> target_func;
     399        std::vector<ptr<Expr>> target_args;
     400        ptr<Stmt> stmt;
     401        ptr<Expr> cond;
     402
     403        WaitForClause( const CodeLocation & loc )
    404404                : StmtClause( loc ) {}
    405405
    406406        const WaitForClause * accept( Visitor & v ) const override { return v.visit( this ); }
    407407  private:
    408     WaitForClause * clone() const override { return new WaitForClause{ *this }; }
    409     MUTATE_FRIEND
     408        WaitForClause * clone() const override { return new WaitForClause{ *this }; }
     409        MUTATE_FRIEND
    410410};
    411411
  • src/AST/Util.cpp

    rf75e25b re5628db  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // Util.hpp -- General utilities for working with the AST.
     7// Util.cpp -- General utilities for working with the AST.
    88//
    99// Author           : Andrew Beach
    1010// Created On       : Wed Jan 19  9:46:00 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Mar 11 18:07:00 2022
    13 // Update Count     : 1
     12// Last Modified On : Wed May 11 16:16:00 2022
     13// Update Count     : 3
    1414//
    1515
     
    4646
    4747/// Check that every note that can has a set CodeLocation.
    48 struct SetCodeLocationsCore {
    49         void previsit( const ParseNode * node ) {
    50                 assert( node->location.isSet() );
     48void isCodeLocationSet( const ParseNode * node ) {
     49        assert( node->location.isSet() );
     50}
     51
     52void areLabelLocationsSet( const Stmt * stmt ) {
     53        for ( const Label& label : stmt->labels ) {
     54                assert( label.location.isSet() );
    5155        }
    52 };
     56}
     57
     58/// Make sure the reference counts are in a valid combination.
     59void isStable( const Node * node ) {
     60        assert( node->isStable() );
     61}
     62
     63/// Check that a FunctionDecl is synchronized with it's FunctionType.
     64void functionDeclMatchesType( const FunctionDecl * decl ) {
     65        // The type is a cache of sorts, if it is missing that is only a
     66        // problem if isTypeFixed is set.
     67        if ( decl->isTypeFixed ) {
     68                assert( decl->type );
     69        } else if ( !decl->type ) {
     70                return;
     71        }
     72
     73        const FunctionType * type = decl->type;
     74
     75        // Check that `type->forall` corresponds with `decl->type_params`.
     76        assert( type->forall.size() == decl->type_params.size() );
     77        // Check that `type->assertions` corresponds with `decl->assertions`.
     78        assert( type->assertions.size() == decl->assertions.size() );
     79        // Check that `type->params` corresponds with `decl->params`.
     80        assert( type->params.size() == decl->params.size() );
     81        // Check that `type->returns` corresponds with `decl->returns`.
     82        assert( type->returns.size() == decl->returns.size() );
     83}
    5384
    5485struct InvariantCore {
     
    5687        // None of the passes should make changes so ordering doesn't matter.
    5788        NoStrongCyclesCore no_strong_cycles;
    58         SetCodeLocationsCore set_code_locations;
    5989
    6090        void previsit( const Node * node ) {
    6191                no_strong_cycles.previsit( node );
     92                isStable( node );
    6293        }
    6394
    6495        void previsit( const ParseNode * node ) {
    65                 no_strong_cycles.previsit( node );
    66                 set_code_locations.previsit( node );
     96                previsit( (const Node *)node );
     97                isCodeLocationSet( node );
     98        }
     99
     100        void previsit( const FunctionDecl * node ) {
     101                previsit( (const ParseNode *)node );
     102                functionDeclMatchesType( node );
     103        }
     104
     105        void previsit( const Stmt * node ) {
     106                previsit( (const ParseNode *)node );
     107                areLabelLocationsSet( node );
    67108        }
    68109
  • src/Common/CodeLocationTools.cpp

    rf75e25b re5628db  
    1010// Created On       : Fri Dec  4 15:42:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Mar 14 15:14:00 2022
    13 // Update Count     : 4
     12// Last Modified On : Wed May 11 16:16:00 2022
     13// Update Count     : 5
    1414//
    1515
     
    2424namespace {
    2525
    26 // There are a lot of helpers in this file that could be used much more
    27 // generally if anyone has another use for them.
    28 
    29 // Check if a node type has a code location.
    30 template<typename node_t>
    31 struct has_code_location : public std::is_base_of<ast::ParseNode, node_t> {};
    32 
    33 template<typename node_t, bool has_location>
    34 struct __GetCL;
    35 
    36 template<typename node_t>
    37 struct __GetCL<node_t, true> {
    38         static inline CodeLocation const * get( node_t const * node ) {
    39                 return &node->location;
    40         }
    41 
    42         static inline CodeLocation * get( node_t * node ) {
    43                 return &node->location;
    44         }
    45 };
    46 
    47 template<typename node_t>
    48 struct __GetCL<node_t, false> {
    49         static inline CodeLocation * get( node_t const * ) {
    50                 return nullptr;
    51         }
    52 };
    53 
    54 template<typename node_t>
    55 CodeLocation const * get_code_location( node_t const * node ) {
    56         return __GetCL< node_t, has_code_location< node_t >::value >::get( node );
    57 }
    58 
    59 template<typename node_t>
    60 CodeLocation * get_code_location( node_t * node ) {
    61         return __GetCL< node_t, has_code_location< node_t >::value >::get( node );
    62 }
    63 
    6426// Fill every location with a nearby (parent) location.
    6527class FillCore : public ast::WithGuards {
    6628        CodeLocation const * parent;
     29
     30        template<typename node_t>
     31        node_t const * parse_visit( node_t const * node ) {
     32                if ( node->location.isUnset() ) {
     33                        assert( parent );
     34                        node_t * newNode = ast::mutate( node );
     35                        newNode->location = *parent;
     36                        return newNode;
     37                }
     38                GuardValue( parent ) = &node->location;
     39                return node;
     40        }
     41
     42        bool hasUnsetLabels( const ast::Stmt * stmt ) {
     43                for ( const ast::Label& label : stmt->labels ) {
     44                        if ( label.location.isUnset() ) {
     45                                return true;
     46                        }
     47                }
     48                return false;
     49        }
     50
     51        template<typename node_t>
     52        node_t const * stmt_visit( node_t const * node ) {
     53                assert( node->location.isSet() );
     54
     55                if ( hasUnsetLabels( node ) ) {
     56                        node_t * newNode = ast::mutate( node );
     57                        for ( ast::Label& label : newNode->labels ) {
     58                                if ( label.location.isUnset() ) {
     59                                        label.location = newNode->location;
     60                                }
     61                        }
     62                        return newNode;
     63                }
     64                return node;
     65        }
     66
     67        template<typename node_t>
     68        auto visit( node_t const * node, long ) {
     69                return node;
     70        }
     71
     72        template<typename node_t>
     73        auto visit( node_t const * node, int ) -> typename
     74                        std::remove_reference< decltype( node->location, node ) >::type {
     75                return parse_visit( node );
     76        }
     77
     78        template<typename node_t>
     79        auto visit( node_t const * node, char ) -> typename
     80                        std::remove_reference< decltype( node->labels, node ) >::type {
     81                return stmt_visit( parse_visit( node ) );
     82        }
     83
    6784public:
    6885        FillCore() : parent( nullptr ) {}
     86        FillCore( const CodeLocation& location ) : parent( &location ) {
     87                assert( location.isSet() );
     88        }
    6989
    7090        template<typename node_t>
    7191        node_t const * previsit( node_t const * node ) {
    72                 GuardValue( parent );
    73                 CodeLocation const * location = get_code_location( node );
    74                 if ( location && location->isUnset() ) {
    75                         assert( parent );
    76                         node_t * newNode = ast::mutate( node );
    77                         CodeLocation * newLocation = get_code_location( newNode );
    78                         assert( newLocation );
    79                         *newLocation = *parent;
    80                         parent = newLocation;
    81                         return newNode;
    82                 } else if ( location ) {
    83                         parent = location;
    84                 }
    85                 return node;
     92                return visit( node, '\0' );
    8693        }
    8794};
     
    233240
    234241        template<typename node_t>
    235         void previsit( node_t const * node ) {
    236                 CodeLocation const * location = get_code_location( node );
    237                 if ( location && location->isUnset() ) {
     242        auto previsit( node_t const * node ) -> decltype( node->location, void() ) {
     243                if ( node->location.isUnset() ) {
    238244                        unset.push_back( node );
    239                 }
    240         }
    241 };
    242 
    243 class LocalFillCore : public ast::WithGuards {
    244         CodeLocation const * parent;
    245 public:
    246         LocalFillCore( CodeLocation const & location ) : parent( &location ) {
    247                 assert( location.isSet() );
    248         }
    249 
    250         template<typename node_t>
    251         auto previsit( node_t const * node )
    252                         -> typename std::enable_if<has_code_location<node_t>::value, node_t const *>::type {
    253                 if ( node->location.isSet() ) {
    254                         GuardValue( parent ) = &node->location;
    255                         return node;
    256                 } else {
    257                         node_t * mut = ast::mutate( node );
    258                         mut->location = *parent;
    259                         return mut;
    260245                }
    261246        }
     
    304289ast::Node const * localFillCodeLocations(
    305290                CodeLocation const & location , ast::Node const * node ) {
    306         ast::Pass<LocalFillCore> visitor( location );
     291        ast::Pass<FillCore> visitor( location );
    307292        return node->accept( visitor );
    308293}
  • src/ControlStruct/LabelGeneratorNew.hpp

    rf75e25b re5628db  
    1818#include <string>                                                                               // for string
    1919
    20 class CodeLocation;
     20struct CodeLocation;
    2121
    2222namespace ast {
  • src/ControlStruct/MultiLevelExit.cpp

    rf75e25b re5628db  
    1818#include "AST/Pass.hpp"
    1919#include "AST/Stmt.hpp"
     20#include "Common/CodeLocationTools.hpp"
    2021#include "LabelGeneratorNew.hpp"
    2122
     
    228229        // Labels on different stmts require different approaches to access
    229230        switch ( stmt->kind ) {
    230           case BranchStmt::Goto:
     231        case BranchStmt::Goto:
    231232                return stmt;
    232           case BranchStmt::Continue:
    233           case BranchStmt::Break: {
    234                   bool isContinue = stmt->kind == BranchStmt::Continue;
    235                   // Handle unlabeled break and continue.
    236                   if ( stmt->target.empty() ) {
    237                           if ( isContinue ) {
    238                                   targetEntry = findEnclosingControlStructure( isContinueTarget );
    239                           } else {
    240                                   if ( enclosing_control_structures.empty() ) {
     233        case BranchStmt::Continue:
     234        case BranchStmt::Break: {
     235                bool isContinue = stmt->kind == BranchStmt::Continue;
     236                // Handle unlabeled break and continue.
     237                if ( stmt->target.empty() ) {
     238                        if ( isContinue ) {
     239                                targetEntry = findEnclosingControlStructure( isContinueTarget );
     240                        } else {
     241                                if ( enclosing_control_structures.empty() ) {
    241242                                          SemanticError( stmt->location,
    242243                                                                         "'break' outside a loop, 'switch', or labelled block" );
    243                                   }
    244                                   targetEntry = findEnclosingControlStructure( isBreakTarget );
    245                           }
    246                           // Handle labeled break and continue.
    247                   } else {
    248                           // Lookup label in table to find attached control structure.
    249                           targetEntry = findEnclosingControlStructure(
    250                                   [ targetStmt = target_table.at(stmt->target) ](auto entry){
     244                                }
     245                                targetEntry = findEnclosingControlStructure( isBreakTarget );
     246                        }
     247                        // Handle labeled break and continue.
     248                } else {
     249                        // Lookup label in table to find attached control structure.
     250                        targetEntry = findEnclosingControlStructure(
     251                                [ targetStmt = target_table.at(stmt->target) ](auto entry){
    251252                                          return entry.stmt == targetStmt;
    252                                   } );
    253                   }
    254                   // Ensure that selected target is valid.
    255                   if ( targetEntry == enclosing_control_structures.rend() || ( isContinue && ! isContinueTarget( *targetEntry ) ) ) {
    256                           SemanticError( stmt->location, toString( (isContinue ? "'continue'" : "'break'"),
     253                                } );
     254                }
     255                // Ensure that selected target is valid.
     256                if ( targetEntry == enclosing_control_structures.rend() || ( isContinue && ! isContinueTarget( *targetEntry ) ) ) {
     257                        SemanticError( stmt->location, toString( (isContinue ? "'continue'" : "'break'"),
    257258                                                        " target must be an enclosing ", (isContinue ? "loop: " : "control structure: "),
    258259                                                        stmt->originalTarget ) );
    259                   }
    260                   break;
    261           }
    262           // handle fallthrough in case/switch stmts
    263           case BranchStmt::FallThrough: {
    264                   targetEntry = findEnclosingControlStructure( isFallthroughTarget );
    265                   // Check that target is valid.
    266                   if ( targetEntry == enclosing_control_structures.rend() ) {
    267                           SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
    268                   }
    269                   if ( ! stmt->target.empty() ) {
    270                           // Labelled fallthrough: target must be a valid fallthough label.
    271                           if ( ! fallthrough_labels.count( stmt->target ) ) {
    272                                   SemanticError( stmt->location, toString( "'fallthrough' target must be a later case statement: ",
     260                }
     261                break;
     262        }
     263        // handle fallthrough in case/switch stmts
     264        case BranchStmt::FallThrough: {
     265                targetEntry = findEnclosingControlStructure( isFallthroughTarget );
     266                // Check that target is valid.
     267                if ( targetEntry == enclosing_control_structures.rend() ) {
     268                        SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
     269                }
     270                if ( ! stmt->target.empty() ) {
     271                        // Labelled fallthrough: target must be a valid fallthough label.
     272                        if ( ! fallthrough_labels.count( stmt->target ) ) {
     273                                SemanticError( stmt->location, toString( "'fallthrough' target must be a later case statement: ",
    273274                                                                                                                   stmt->originalTarget ) );
    274                           }
    275                           return new BranchStmt( stmt->location, BranchStmt::Goto, stmt->originalTarget );
    276                   }
    277                   break;
    278           }
    279           case BranchStmt::FallThroughDefault: {
    280                   targetEntry = findEnclosingControlStructure( isFallthroughDefaultTarget );
    281 
    282                   // Check if in switch or choose statement.
    283                   if ( targetEntry == enclosing_control_structures.rend() ) {
    284                           SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
    285                   }
    286 
    287                   // Check if switch or choose has default clause.
    288                   auto switchStmt = strict_dynamic_cast< const SwitchStmt * >( targetEntry->stmt );
    289                   bool foundDefault = false;
    290                   for ( auto caseStmt : switchStmt->cases ) {
    291                           if ( caseStmt->isDefault() ) {
    292                                   foundDefault = true;
    293                                   break;
    294                           }
    295                   }
    296                   if ( ! foundDefault ) {
    297                           SemanticError( stmt->location, "'fallthrough default' must be enclosed in a 'switch' or 'choose'"
    298                                                         "control structure with a 'default' clause" );
    299                   }
    300                   break;
    301           }
    302           default:
     275                        }
     276                        return new BranchStmt( stmt->location, BranchStmt::Goto, stmt->originalTarget );
     277                }
     278                break;
     279        }
     280        case BranchStmt::FallThroughDefault: {
     281                targetEntry = findEnclosingControlStructure( isFallthroughDefaultTarget );
     282
     283                // Check if in switch or choose statement.
     284                if ( targetEntry == enclosing_control_structures.rend() ) {
     285                        SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
     286                }
     287
     288                // Check if switch or choose has default clause.
     289                auto switchStmt = strict_dynamic_cast< const SwitchStmt * >( targetEntry->stmt );
     290                bool foundDefault = false;
     291                for ( auto caseStmt : switchStmt->cases ) {
     292                        if ( caseStmt->isDefault() ) {
     293                                foundDefault = true;
     294                                break;
     295                        }
     296                }
     297                if ( ! foundDefault ) {
     298                        SemanticError( stmt->location, "'fallthrough default' must be enclosed in a 'switch' or 'choose'"
     299                                                  "control structure with a 'default' clause" );
     300                }
     301                break;
     302        }
     303        default:
    303304                assert( false );
    304305        }
     
    307308        Label exitLabel( CodeLocation(), "" );
    308309        switch ( stmt->kind ) {
    309           case BranchStmt::Break:
     310        case BranchStmt::Break:
    310311                assert( ! targetEntry->useBreakExit().empty() );
    311312                exitLabel = targetEntry->useBreakExit();
    312313                break;
    313           case BranchStmt::Continue:
     314        case BranchStmt::Continue:
    314315                assert( ! targetEntry->useContExit().empty() );
    315316                exitLabel = targetEntry->useContExit();
    316317                break;
    317           case BranchStmt::FallThrough:
     318        case BranchStmt::FallThrough:
    318319                assert( ! targetEntry->useFallExit().empty() );
    319320                exitLabel = targetEntry->useFallExit();
    320321                break;
    321           case BranchStmt::FallThroughDefault:
     322        case BranchStmt::FallThroughDefault:
    322323                assert( ! targetEntry->useFallDefaultExit().empty() );
    323324                exitLabel = targetEntry->useFallDefaultExit();
     
    327328                }
    328329                break;
    329           default:
     330        default:
    330331                assert(0);
    331332        }
     
    633634        Pass<MultiLevelExitCore> visitor( labelTable );
    634635        const CompoundStmt * ret = stmt->accept( visitor );
    635         return ret;
     636        // There are some unset code locations slipping in, possibly by Labels.
     637        const Node * node = localFillCodeLocations( ret->location, ret );
     638        return strict_dynamic_cast<const CompoundStmt *>( node );
    636639}
    637640} // namespace ControlStruct
  • src/Parser/parser.yy

    rf75e25b re5628db  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed May  4 14:25:20 2022
    13 // Update Count     : 5277
     12// Last Modified On : Wed May  4 17:22:48 2022
     13// Update Count     : 5279
    1414//
    1515
     
    12241224                { $$ = new StatementNode( build_while( new CondCtl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); }
    12251225        | WHILE '(' ')' statement ELSE statement                        // CFA
    1226                 { $$ = new StatementNode( build_while( new CondCtl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); SemanticWarning( yylloc, Warning::SuperfluousElse ); }
     1226                {
     1227                        $$ = new StatementNode( build_while( new CondCtl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) );
     1228                        SemanticWarning( yylloc, Warning::SuperfluousElse );
     1229                }
    12271230        | WHILE '(' conditional_declaration ')' statement       %prec THEN
    12281231                { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ) ) ); }
     
    12321235                { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); }
    12331236        | DO statement WHILE '(' ')' ELSE statement                     // CFA
    1234                 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); SemanticWarning( yylloc, Warning::SuperfluousElse ); }
    1235         | DO statement WHILE '(' comma_expression ')' ';'       %prec THEN
     1237                {
     1238                        $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) );
     1239                        SemanticWarning( yylloc, Warning::SuperfluousElse );
     1240                }
     1241        | DO statement WHILE '(' comma_expression ')' ';'
    12361242                { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
    12371243        | DO statement WHILE '(' comma_expression ')' ELSE statement // CFA
    12381244                { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ), $8 ) ); }
    1239         | FOR '(' ')' statement                                                         // CFA => for ( ;; )
     1245        | FOR '(' ')' statement                                                         %prec THEN // CFA => for ( ;; )
    12401246                { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); }
    1241         | FOR '(' ')' statement ELSE statement                  // CFA
    1242                 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); SemanticWarning( yylloc, Warning::SuperfluousElse ); }
     1247        | FOR '(' ')' statement ELSE statement                          // CFA
     1248                {
     1249                        $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) );
     1250                        SemanticWarning( yylloc, Warning::SuperfluousElse );
     1251                }
    12431252        | FOR '(' for_control_expression_list ')' statement     %prec THEN
    12441253                { $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ) ) ); }
  • src/Validate/Autogen.cpp

    rf75e25b re5628db  
    350350                name,
    351351                std::move( type_params ),
     352                std::move( assertions ),
    352353                std::move( params ),
    353354                std::move( returns ),
     
    360361                // Auto-generated routines are inline to avoid conflicts.
    361362                ast::Function::Specs( ast::Function::Inline ) );
    362         decl->assertions = std::move( assertions );
    363363        decl->fixUniqueId();
    364364        return decl;
  • tests/include/.expect/includes.nast.txt

    rf75e25b re5628db  
    1 include/includes.cfa:153:25: warning: Compiled
     1include/includes.cfa:169:25: warning: Compiled
  • tests/include/includes.cfa

    rf75e25b re5628db  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb  3 22:06:07 2022
    13 // Update Count     : 774
     12// Last Modified On : Tue May 10 16:36:44 2022
     13// Update Count     : 776
    1414//
    1515
     
    3232#include <crypt.h>
    3333#include <ctype.h>
    34 //#include <curses.h>                                                                           // may not be installed
     34#if __has_include( "curses.h" )
     35#include <curses.h>                                                                             // may not be installed
     36#endif
    3537#include <dirent.h>
    3638#include <dlfcn.h>
     
    4143#include <errno.h>
    4244#include <error.h>
    43 //#include <eti.h>                                                                              // may not be installed, comes with ncurses
     45#if __has_include( "eti.h" )
     46#include <eti.h>                                                                                // may not be installed, comes with ncurses
     47#endif
    4448#include <execinfo.h>
    4549#include <expat.h>
     
    5054#include <fmtmsg.h>
    5155#include <fnmatch.h>
    52 //#include <form.h>                                                                             // may not be installed, comes with ncurses
     56#if __has_include( "form.h" )
     57#include <form.h>                                                                               // may not be installed, comes with ncurses
     58#endif
    5359#include <fstab.h>
    5460#include <fts.h>
     
    7884#include <mcheck.h>
    7985#include <memory.h>
    80 //#include <menu.h>                                                                             // may not be installed, comes with ncurses
     86#if __has_include( "menu.h" )
     87#include <menu.h>                                                                               // may not be installed, comes with ncurses
     88#endif
    8189#include <mntent.h>
    8290#include <monetary.h>
    8391#include <mqueue.h>
    84 //#include <ncurses_dll.h>                                                              // may not be installed, comes with ncurses
     92#if __has_include( "ncurses_dll.h" )
     93#include <ncurses_dll.h>                                                                // may not be installed, comes with ncurses
     94#endif
    8595#include <netdb.h>
    8696#include <nl_types.h>
    8797#include <nss.h>
    8898#include <obstack.h>
    89 //#include <panel.h>                                                                            // may not be installed, comes with ncurses
     99#if __has_include( "panel.h" )
     100#include <panel.h>                                                                              // may not be installed, comes with ncurses
     101#endif
    90102#include <paths.h>
    91103#include <poll.h>
     
    118130#include <syslog.h>
    119131#include <tar.h>
    120 //#include <term.h>                                                                             // may not be installed, comes with ncurses
    121 //#include <termcap.h>                                                                  // may not be installed, comes with ncurses
     132#if __has_include( "term.h" )
     133#include <term.h>                                                                               // may not be installed, comes with ncurses
     134#include <termcap.h>                                                                    // may not be installed, comes with ncurses
     135#endif
    122136#include <termio.h>
    123137#include <termios.h>
     
    131145#include <ucontext.h>
    132146#include <ulimit.h>
    133 //#include <unctrl.h>                                                                           // may not be installed, comes with ncurses
     147#if __has_include( "unctrl.h" )
     148#include <unctrl.h>                                                                             // may not be installed, comes with ncurses
     149#endif
    134150#include <unistd.h>
    135151#include <utime.h>
Note: See TracChangeset for help on using the changeset viewer.