@@ -755,12 +755,19 @@ PointerVariableConstraint::mkString(Constraints &CS,
755
755
UNPACK_OPTS (EmitName, ForItype, EmitPointee, UnmaskTypedef, UseName,
756
756
ForItypeBase);
757
757
758
+ // This function has become pretty ad-hoc and has a number of known bugs: see
759
+ // https://github.com/correctcomputation/checkedc-clang/issues/703. We hope to
760
+ // overhaul it in the future.
761
+
758
762
// The name field encodes if this variable is the return type for a function.
759
763
// TODO: store this information in a separate field.
760
764
bool IsReturn = getName () == RETVAR;
761
765
762
- if (UseName.empty ())
766
+ if (UseName.empty ()) {
763
767
UseName = getName ();
768
+ if (UseName.empty ())
769
+ EmitName = false ;
770
+ }
764
771
765
772
if (IsTypedef && !UnmaskTypedef) {
766
773
std::string QualTypedef = gatherQualStrings () + TypedefString;
@@ -787,13 +794,9 @@ PointerVariableConstraint::mkString(Constraints &CS,
787
794
bool EmittedBase = false ;
788
795
// Have we emitted the name of the variable yet?
789
796
bool EmittedName = false ;
790
- // Was the last variable an Array?
791
- bool PrevArr = false ;
792
- // Is the entire type so far an array?
793
- bool AllArrays = true ;
794
797
if (!EmitName || IsReturn)
795
798
EmittedName = true ;
796
- uint32_t TypeIdx = 0 ;
799
+ int TypeIdx = 0 ;
797
800
798
801
// If we've set a GenericIndex for void, it means we're converting it into
799
802
// a generic function so give it the default generic type name.
@@ -807,16 +810,15 @@ PointerVariableConstraint::mkString(Constraints &CS,
807
810
}
808
811
809
812
auto It = Vars.begin ();
810
- auto I = 0 ;
811
813
// Skip over first pointer level if only emitting pointee string.
812
814
// This is needed when inserting type arguments.
813
815
if (EmitPointee)
814
816
++It;
815
817
// Iterate through the vars(), but if we have an internal typedef, then stop
816
818
// once you reach the typedef's level.
817
819
for (; It != Vars.end () && IMPLIES (TypedefLevelInfo.HasTypedef ,
818
- I < TypedefLevelInfo.TypedefLevel );
819
- ++It, I ++) {
820
+ TypeIdx < TypedefLevelInfo.TypedefLevel );
821
+ ++It, TypeIdx ++) {
820
822
const auto &V = *It;
821
823
ConstAtom *C = nullptr ;
822
824
if (ForItypeBase) {
@@ -838,21 +840,23 @@ PointerVariableConstraint::mkString(Constraints &CS,
838
840
if (!ForItype && InferredGenericIndex == -1 && isVoidPtr ())
839
841
K = Atom::A_Wild;
840
842
841
- if (PrevArr && ArrSizes.at (TypeIdx).first != O_SizedArray && !EmittedName) {
842
- EmittedName = true ;
843
+ // In a case like `_Ptr<TYPE> p[2]`, the ` p[2]` needs to end up _after_ the
844
+ // `>`, so we need to push the ` p[2]` onto EndStrs _before_ the code below
845
+ // pushes the `>`. In general, before we visit a checked pointer level (not
846
+ // a checked array level), we need to transfer any pending array levels and
847
+ // emit the name (if applicable).
848
+ if (K != Atom::A_Wild && ArrSizes.at (TypeIdx).first != O_SizedArray) {
843
849
addArrayAnnotations (ConstArrs, EndStrs);
844
- EndStrs.push_front (" " + UseName);
850
+ if (!EmittedName) {
851
+ EmittedName = true ;
852
+ EndStrs.push_front (" " + UseName);
853
+ }
845
854
}
846
- PrevArr = ArrSizes.at (TypeIdx).first == O_SizedArray;
847
855
848
856
switch (K) {
849
857
case Atom::A_Ptr:
850
858
getQualString (TypeIdx, Ss);
851
859
852
- // We need to check and see if this level of variable
853
- // is constrained by a bounds safe interface. If it is,
854
- // then we shouldn't re-write it.
855
- AllArrays = false ;
856
860
EmittedBase = false ;
857
861
Ss << " _Ptr<" ;
858
862
EndStrs.push_front (" >" );
@@ -866,38 +870,28 @@ PointerVariableConstraint::mkString(Constraints &CS,
866
870
// we should substitute [K].
867
871
if (emitArraySize (ConstArrs, TypeIdx, K))
868
872
break ;
869
- AllArrays = false ;
870
- // We need to check and see if this level of variable
871
- // is constrained by a bounds safe interface. If it is,
872
- // then we shouldn't re-write it.
873
873
EmittedBase = false ;
874
874
Ss << " _Array_ptr<" ;
875
875
EndStrs.push_front (" >" );
876
876
break ;
877
877
case Atom::A_NTArr:
878
+ // If this is an NTArray.
879
+ getQualString (TypeIdx, Ss);
878
880
if (emitArraySize (ConstArrs, TypeIdx, K))
879
881
break ;
880
- AllArrays = false ;
881
- // This additional check is to prevent fall-through from the array.
882
- if (K == Atom::A_NTArr) {
883
- // If this is an NTArray.
884
- getQualString (TypeIdx, Ss);
885
882
886
- // We need to check and see if this level of variable
887
- // is constrained by a bounds safe interface. If it is,
888
- // then we shouldn't re-write it.
889
- EmittedBase = false ;
890
- Ss << " _Nt_array_ptr<" ;
891
- EndStrs.push_front (" >" );
892
- break ;
893
- }
894
- LLVM_FALLTHROUGH;
883
+ EmittedBase = false ;
884
+ Ss << " _Nt_array_ptr<" ;
885
+ EndStrs.push_front (" >" );
886
+ break ;
895
887
// If there is no array in the original program, then we fall through to
896
888
// the case where we write a pointer value.
897
889
case Atom::A_Wild:
898
890
if (emitArraySize (ConstArrs, TypeIdx, K))
899
891
break ;
900
- AllArrays = false ;
892
+ // FIXME: This code emits wild pointer levels with the outermost on the
893
+ // left. The outermost should be on the right
894
+ // (https://github.com/correctcomputation/checkedc-clang/issues/161).
901
895
if (FV != nullptr ) {
902
896
FptrInner << " *" ;
903
897
getQualString (TypeIdx, FptrInner);
@@ -917,35 +911,19 @@ PointerVariableConstraint::mkString(Constraints &CS,
917
911
llvm_unreachable (" impossible" );
918
912
break ;
919
913
}
920
- TypeIdx++;
921
- }
922
-
923
- // If the previous variable was an array or
924
- // if we are leaving an array run, we need to emit the
925
- // annotation for a stack-array
926
- if (PrevArr && !ConstArrs.empty ())
927
- addArrayAnnotations (ConstArrs, EndStrs);
928
-
929
- // If the whole type is an array so far, and we haven't emitted
930
- // a name yet, then emit the name so that it appears before
931
- // the the stack array type.
932
- if (PrevArr && !EmittedName && AllArrays) {
933
- EmittedName = true ;
934
- EndStrs.push_front (" " + UseName);
935
914
}
936
915
937
916
if (!EmittedBase) {
938
917
// If we have a FV pointer, then our "base" type is a function pointer type.
939
918
if (FV) {
940
- if (Ss.str ().empty ()) {
941
- if (!EmittedName) {
942
- FptrInner << UseName;
943
- EmittedName = true ;
944
- }
945
- for (std::string Str : EndStrs)
946
- FptrInner << Str;
947
- EndStrs.clear ();
919
+ if (!EmittedName) {
920
+ FptrInner << UseName;
921
+ EmittedName = true ;
948
922
}
923
+ std::deque<std::string> FptrEndStrs;
924
+ addArrayAnnotations (ConstArrs, FptrEndStrs);
925
+ for (std::string Str : FptrEndStrs)
926
+ FptrInner << Str;
949
927
bool EmitFVName = !FptrInner.str ().empty ();
950
928
if (EmitFVName)
951
929
Ss << FV->mkString (CS, MKSTRING_OPTS (UseName = FptrInner.str (),
@@ -963,27 +941,20 @@ PointerVariableConstraint::mkString(Constraints &CS,
963
941
}
964
942
}
965
943
966
- // Add closing elements to type
967
- for (std::string Str : EndStrs) {
968
- Ss << Str;
969
- }
970
-
971
944
// No space after itype.
972
- if (!EmittedName && !UseName. empty () ) {
945
+ if (!EmittedName) {
973
946
if (!StringRef (Ss.str ()).endswith (" *" ))
974
947
Ss << " " ;
975
948
Ss << UseName;
976
949
}
977
950
978
- // Final array dropping.
979
- if (!ConstArrs.empty ()) {
980
- std::deque<std::string> ArrStrs;
981
- addArrayAnnotations (ConstArrs, ArrStrs);
982
- for (std::string Str : ArrStrs)
983
- Ss << Str;
951
+ // Add closing elements to type
952
+ addArrayAnnotations (ConstArrs, EndStrs);
953
+ for (std::string Str : EndStrs) {
954
+ Ss << Str;
984
955
}
985
956
986
- if (IsReturn && !ForItype)
957
+ if (IsReturn && !ForItype && ! StringRef (Ss. str ()). endswith ( " * " ) )
987
958
Ss << " " ;
988
959
989
960
return Ss.str ();
0 commit comments