@@ -250,6 +250,21 @@ PointerVariableConstraint::PointerVariableConstraint(const QualType &QT,
250
250
ArrPresent = IsArr = true ;
251
251
IsIncompleteArr = Ty->isIncompleteArrayType ();
252
252
253
+ // Boil off the typedefs in the array case.
254
+ // TODO this will need to change to properly account for typedefs
255
+ bool boiling = true ;
256
+ while (boiling) {
257
+ if (const TypedefType *TydTy = dyn_cast<TypedefType>(Ty)) {
258
+ QTy = TydTy->desugar ();
259
+ Ty = QTy.getTypePtr ();
260
+ } else if (const ParenType *ParenTy = dyn_cast<ParenType>(Ty)) {
261
+ QTy = ParenTy->desugar ();
262
+ Ty = QTy.getTypePtr ();
263
+ } else {
264
+ boiling = false ;
265
+ }
266
+ }
267
+
253
268
// See if there is a constant size to this array type at this position.
254
269
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty)) {
255
270
arrSizes[TypeIdx] = std::pair<OriginalArrType,uint64_t >(
@@ -259,11 +274,6 @@ PointerVariableConstraint::PointerVariableConstraint(const QualType &QT,
259
274
O_UnSizedArray,0 );
260
275
}
261
276
262
- // Boil off the typedefs in the array case.
263
- while (const TypedefType *TydTy = dyn_cast<TypedefType>(Ty)) {
264
- QTy = TydTy->desugar ();
265
- Ty = QTy.getTypePtr ();
266
- }
267
277
268
278
// Iterate.
269
279
if (const ArrayType *ArrTy = dyn_cast<ArrayType>(Ty)) {
@@ -447,10 +457,17 @@ void PointerVariableConstraint::insertQualType(uint32_t TypeIdx,
447
457
QualMap[TypeIdx].insert (RestrictQualification);
448
458
}
449
459
450
- bool PointerVariableConstraint::emitArraySize (std::ostringstream &Pss,
460
+
461
+ // emitArraySize
462
+ // Take an array or nt_array variable, determines if it is
463
+ // a constant array, and if so emits the apprioate syntax for a
464
+ // stack-based array. This functions also updates various flags.
465
+ bool PointerVariableConstraint::emitArraySize (std::stack<std::string> &CheckedArrs,
451
466
uint32_t TypeIdx,
452
- bool &EmitName,
453
- bool &EmittedCheckedAnnotation,
467
+ // Is the type only an array
468
+ bool &AllArrays,
469
+ // Are we processing an array
470
+ bool &ArrayRun,
454
471
bool Nt) {
455
472
bool Ret = false ;
456
473
if (ArrPresent) {
@@ -459,31 +476,39 @@ bool PointerVariableConstraint::emitArraySize(std::ostringstream &Pss,
459
476
OriginalArrType Oat = i->second .first ;
460
477
uint64_t Oas = i->second .second ;
461
478
462
- if (EmitName == false ) {
463
- EmitName = true ;
464
- Pss << getName ();
465
- }
479
+ std::ostringstream SizeStr;
466
480
467
- switch (Oat) {
468
- case O_SizedArray:
469
- if (!EmittedCheckedAnnotation) {
470
- Pss << (Nt ? " _Nt_checked" : " _Checked" );
471
- EmittedCheckedAnnotation = true ;
472
- }
473
- Pss << " [" << Oas << " ]" ;
474
- Ret = true ;
475
- break ;
476
- /* case O_UnSizedArray:
477
- Pss << "[]";
478
- Ret = true;
479
- break;*/
480
- default : break ;
481
+ if (Oat == O_SizedArray) {
482
+ SizeStr << (Nt ? " _Nt_checked" : " _Checked" );
483
+ SizeStr << " [" << Oas << " ]" ;
484
+ CheckedArrs.push (SizeStr.str ());
485
+ ArrayRun = true ;
486
+ Ret = true ;
487
+ } else {
488
+ AllArrays = ArrayRun = false ;
481
489
}
490
+
482
491
return Ret;
483
492
}
484
493
return Ret;
485
494
}
486
495
496
+
497
+ /* addArrayAnnotiations
498
+ * This function takes all the stacked annotations for constant arrays
499
+ * and pops them onto the EndStrs, this ensures the right order of annotations
500
+ * */
501
+ void PointerVariableConstraint::addArrayAnnotations (
502
+ std::stack<std::string> &CheckedArrs,
503
+ std::deque<std::string> &EndStrs) {
504
+ while (!CheckedArrs.empty ()) {
505
+ auto NextStr = CheckedArrs.top ();
506
+ CheckedArrs.pop ();
507
+ EndStrs.push_front (NextStr);
508
+ }
509
+ assert (CheckedArrs.empty ());
510
+ }
511
+
487
512
// Mesh resolved constraints with the PointerVariableConstraints set of
488
513
// variables and potentially nested function pointer declaration. Produces a
489
514
// string that can be replaced in the source code.
@@ -493,12 +518,25 @@ PointerVariableConstraint::mkString(EnvironmentMap &E,
493
518
bool ForItype,
494
519
bool EmitPointee) {
495
520
std::ostringstream Ss;
496
- std::ostringstream Pss;
497
- unsigned CaratsToAdd = 0 ;
521
+ // This deque will store all the type strings that need to pushed
522
+ // to the end of the type string. This is typically things like
523
+ // closing delimiters.
524
+ std::deque<std::string> EndStrs;
525
+ // This will store stacked array decls to ensure correct order
526
+ // We encounter constant arrays variables in the reverse order they
527
+ // need to appear in, so the LIFO structure reverses these annotations
528
+ std::stack<std::string> CheckedArrs;
529
+ // Have we emitted the string for the base type
498
530
bool EmittedBase = false ;
531
+ // Have we emitted the name of the variable yet?
499
532
bool EmittedName = false ;
500
- bool EmittedCheckedAnnotation = false ;
501
- if (EmitName == false && hasItype () == false )
533
+ // Was the last variable an Array?
534
+ bool PrevArr = false ;
535
+ // Is the entire type so far an array?
536
+ bool AllArrays = true ;
537
+ // Are we in a sequence of arrays
538
+ bool ArrayRun = false ;
539
+ if ((EmitName == false && hasItype () == false ) || getName () == RETVAR)
502
540
EmittedName = true ;
503
541
uint32_t TypeIdx = 0 ;
504
542
@@ -527,17 +565,28 @@ PointerVariableConstraint::mkString(EnvironmentMap &E,
527
565
if (!ForItype && BaseType == " void" )
528
566
K = Atom::A_Wild;
529
567
568
+ if (PrevArr && K != Atom::A_Arr && !EmittedName) {
569
+ EmittedName = true ;
570
+ addArrayAnnotations (CheckedArrs, EndStrs);
571
+ EndStrs.push_front (" " + getName ());
572
+ }
573
+ PrevArr = ((K == Atom::A_Arr || K == Atom::A_NTArr)
574
+ && ArrPresent
575
+ && arrSizes[TypeIdx].first == O_SizedArray);
576
+
530
577
switch (K) {
531
578
case Atom::A_Ptr:
532
579
getQualString (TypeIdx, Ss);
533
580
534
581
// We need to check and see if this level of variable
535
582
// is constrained by a bounds safe interface. If it is,
536
583
// then we shouldn't re-write it.
584
+ AllArrays = false ;
537
585
if (hasItype () == false ) {
538
586
EmittedBase = false ;
539
587
Ss << " _Ptr<" ;
540
- CaratsToAdd++;
588
+ ArrayRun = false ;
589
+ EndStrs.push_front (" >" );
541
590
break ;
542
591
}
543
592
LLVM_FALLTHROUGH;
@@ -548,23 +597,21 @@ PointerVariableConstraint::mkString(EnvironmentMap &E,
548
597
// be [] instead of *, IF, the original type was an array.
549
598
// And, if the original type was a sized array of size K.
550
599
// we should substitute [K].
551
- if (emitArraySize (Pss, TypeIdx, EmittedName,
552
- EmittedCheckedAnnotation, false ))
600
+ if (emitArraySize (CheckedArrs, TypeIdx, AllArrays, ArrayRun, false ))
553
601
break ;
554
602
// We need to check and see if this level of variable
555
603
// is constrained by a bounds safe interface. If it is,
556
604
// then we shouldn't re-write it.
557
605
if (hasItype () == false ) {
558
606
EmittedBase = false ;
559
607
Ss << " _Array_ptr<" ;
560
- CaratsToAdd++ ;
608
+ EndStrs. push_front ( " > " ) ;
561
609
break ;
562
610
}
563
611
LLVM_FALLTHROUGH;
564
612
case Atom::A_NTArr:
565
613
566
- if (emitArraySize (Pss, TypeIdx, EmittedName,
567
- EmittedCheckedAnnotation, true ))
614
+ if (emitArraySize (CheckedArrs, TypeIdx, AllArrays, ArrayRun, true ))
568
615
break ;
569
616
// This additional check is to prevent fall-through from the array.
570
617
if (K == Atom::A_NTArr) {
@@ -577,14 +624,18 @@ PointerVariableConstraint::mkString(EnvironmentMap &E,
577
624
if (hasItype () == false ) {
578
625
EmittedBase = false ;
579
626
Ss << " _Nt_array_ptr<" ;
580
- CaratsToAdd++ ;
627
+ EndStrs. push_front ( " > " ) ;
581
628
break ;
582
629
}
583
630
}
584
631
LLVM_FALLTHROUGH;
585
632
// If there is no array in the original program, then we fall through to
586
633
// the case where we write a pointer value.
587
634
case Atom::A_Wild:
635
+ AllArrays = false ;
636
+ if (ArrayRun)
637
+ addArrayAnnotations (CheckedArrs, EndStrs);
638
+ ArrayRun = false ;
588
639
if (EmittedBase) {
589
640
Ss << " *" ;
590
641
} else {
@@ -607,6 +658,22 @@ PointerVariableConstraint::mkString(EnvironmentMap &E,
607
658
TypeIdx++;
608
659
}
609
660
661
+ // If the previous variable was an array or
662
+ // if we are leaving an array run, we need to emit the
663
+ // annotation for a stack-array
664
+ if ((PrevArr || ArrayRun) && !CheckedArrs.empty ())
665
+ addArrayAnnotations (CheckedArrs, EndStrs);
666
+
667
+ // If the whole type is an array so far, and we haven't emitted
668
+ // a name yet, then emit the name so that it appears before
669
+ // the the stack array type.
670
+ if (PrevArr && !EmittedName && AllArrays) {
671
+ EmittedName = true ;
672
+ EndStrs.push_front (" " + getName ());
673
+ }
674
+
675
+
676
+
610
677
if (EmittedBase == false ) {
611
678
// If we have a FV pointer, then our "base" type is a function pointer.
612
679
// type.
@@ -617,25 +684,24 @@ PointerVariableConstraint::mkString(EnvironmentMap &E,
617
684
}
618
685
}
619
686
620
- // Push carats onto the end of the string.
621
- for (unsigned i = 0 ; i < CaratsToAdd; i++ ) {
622
- Ss << " > " ;
687
+ // Add closing elements to type
688
+ for (std::string Str : EndStrs ) {
689
+ Ss << Str ;
623
690
}
624
691
625
692
// No space after itype.
626
- if (!ForItype )
627
- Ss << " " ;
693
+ if (!EmittedName )
694
+ Ss << " " << getName () ;
628
695
629
- std::string FinalDec;
630
- if (EmittedName == false ) {
631
- if (getName () != RETVAR)
632
- Ss << getName ();
633
- FinalDec = Ss.str ();
634
- } else {
635
- FinalDec = Ss.str () + Pss.str ();
636
- }
696
+ // Final array dropping
697
+ if (!CheckedArrs.empty ())
698
+ addArrayAnnotations (CheckedArrs, EndStrs);
699
+
700
+ // TODO remove comparison to RETVAR
701
+ if (getName () == RETVAR && !ForItype)
702
+ Ss << " " ;
637
703
638
- return FinalDec ;
704
+ return Ss. str () ;
639
705
}
640
706
641
707
bool PVConstraint::addArgumentConstraint (ConstraintVariable *DstCons,
0 commit comments