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