Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions clang/include/clang/3C/ConstraintVariables.h
Original file line number Diff line number Diff line change
Expand Up @@ -365,8 +365,9 @@ class PointerVariableConstraint : public ConstraintVariable {
bool IsZeroWidthArray;

bool IsTypedef = false;
TypedefNameDecl *TDT;
std::string TypedefString;
ConstraintVariable *TypedefVar;

// Does the type internally contain a typedef, and if so: at what level and
// what is it's name?
struct InternalTypedefInfo TypedefLevelInfo;
Expand All @@ -381,7 +382,7 @@ class PointerVariableConstraint : public ConstraintVariable {
ConstraintVariable(PointerVariable, "", Name), FV(nullptr),
SrcHasItype(false), PartOfFuncPrototype(false), Parent(nullptr),
SourceGenericIndex(-1), InferredGenericIndex(-1),
IsZeroWidthArray(false), IsTypedef(false), TDT(nullptr),
IsZeroWidthArray(false), IsTypedef(false),
TypedefLevelInfo({}), IsVoidPtr(false) {}

public:
Expand All @@ -392,8 +393,9 @@ class PointerVariableConstraint : public ConstraintVariable {
// Check if any of the pointers is either a sized or unsized arr.
bool hasSomeSizedArr() const;

bool isTypedef(void);
void setTypedef(TypedefNameDecl *T, std::string S);
bool isTypedef(void) const;
const ConstraintVariable *getTypedefVar() const;
void setTypedef(ConstraintVariable *TypedefVar, std::string S);

// Return true if this constraint had an itype in the original source code.
bool srcHasItype() const override { return SrcHasItype; }
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/3C/ProgramInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ class ProgramInfo : public ProgramVariableAdder {
PointerVariableConstraint *PV);

void unifyIfTypedef(const clang::Type *, clang::ASTContext &,
clang::DeclaratorDecl *, PVConstraint *);
PVConstraint *, ConsAction CA = Same_to_Same);

CVarOption lookupTypedef(PersistentSourceLoc PSL);

Expand Down
27 changes: 19 additions & 8 deletions clang/lib/3C/ConstraintVariables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ PointerVariableConstraint::PointerVariableConstraint(
SourceGenericIndex(Ot->SourceGenericIndex),
InferredGenericIndex(Ot->InferredGenericIndex),
IsZeroWidthArray(Ot->IsZeroWidthArray),
IsTypedef(Ot->IsTypedef), TDT(Ot->TDT), TypedefString(Ot->TypedefString),
IsTypedef(Ot->IsTypedef), TypedefString(Ot->TypedefString),
TypedefLevelInfo(Ot->TypedefLevelInfo), IsVoidPtr(Ot->IsVoidPtr) {
// These are fields of the super class Constraint Variable
this->HasEqArgumentConstraints = Ot->HasEqArgumentConstraints;
Expand Down Expand Up @@ -206,8 +206,7 @@ PointerVariableConstraint::PointerVariableConstraint(
const ASTContext &C, std::string *InFunc, int ForceGenericIndex,
bool PotentialGeneric,
bool VarAtomForChecked, TypeSourceInfo *TSInfo, const QualType &ITypeT)
: ConstraintVariable(ConstraintVariable::PointerVariable,
tyToStr(QT.getTypePtr()), N),
: ConstraintVariable(ConstraintVariable::PointerVariable, qtyToStr(QT), N),
FV(nullptr), SrcHasItype(false), PartOfFuncPrototype(InFunc != nullptr),
Parent(nullptr) {
QualType QTy = QT;
Expand Down Expand Up @@ -704,12 +703,20 @@ void PointerVariableConstraint::addArrayAnnotations(
assert(ConstArrs.empty());
}

bool PointerVariableConstraint::isTypedef(void) { return IsTypedef; }
bool PointerVariableConstraint::isTypedef(void) const { return IsTypedef; }

void PointerVariableConstraint::setTypedef(TypedefNameDecl *T, std::string S) {
void
PointerVariableConstraint::setTypedef(ConstraintVariable *TypedefVar,
std::string S) {
IsTypedef = true;
TDT = T;
TypedefString = S;
this->TypedefVar = TypedefVar;
}

const ConstraintVariable *
PointerVariableConstraint::getTypedefVar() const {
assert(isTypedef());
return this->TypedefVar;
}

// Mesh resolved constraints with the PointerVariableConstraints set of
Expand All @@ -736,8 +743,12 @@ PointerVariableConstraint::mkString(Constraints &CS,
UseName = getName();

if (IsTypedef && !UnmaskTypedef) {
return gatherQualStrings() + TypedefString +
(EmitName && !IsReturn ? (" " + UseName) : " ");
std::string QualTypedef = gatherQualStrings() + TypedefString;
if (!ForItype)
QualTypedef += " ";
if (EmitName && !IsReturn)
QualTypedef += UseName;
return QualTypedef;
}

std::ostringstream Ss;
Expand Down
25 changes: 21 additions & 4 deletions clang/lib/3C/DeclRewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,33 @@ using namespace clang;
void DeclRewriter::buildItypeDecl(PVConstraint *Defn, DeclaratorDecl *Decl,
std::string &Type, std::string &IType,
ProgramInfo &Info, ArrayBoundsRewriter &ABR) {
const EnvironmentMap &Env = Info.getConstraints().getVariables();
bool IsTypedefVarUnchecked =
Defn->isTypedef() && (ItypesForExtern ||
!Defn->getTypedefVar()->isSolutionChecked(Env));
if (Defn->getFV()) {
// This declaration is for a function pointer. Writing itypes on function
// pointers is a little bit harder since the original type string will not
// work for the unchecked portion of the itype. We need to generate the
// unchecked type from the PVConstraint. The last argument of this call
// tells mkString to generate a string using unchecked types instead of
// checked types.
Type = Defn->mkString(Info.getConstraints(),
MKSTRING_OPTS(ForItypeBase = true));
if (Defn->isTypedef() && !IsTypedefVarUnchecked)
Type = Defn->mkString(Info.getConstraints(),
MKSTRING_OPTS(UnmaskTypedef = true,
ForItypeBase = true));
else
Type = Defn->mkString(Info.getConstraints(),
MKSTRING_OPTS(ForItypeBase = true));
} else {
Type = Defn->getRewritableOriginalTy();
if (Defn->isTypedef() && !IsTypedefVarUnchecked)
Type = Defn->mkString(Info.getConstraints(),
MKSTRING_OPTS(UnmaskTypedef = true,
ForItypeBase = true,
EmitName = false));
else
Type = Defn->getRewritableOriginalTy();

if (isa_and_nonnull<ParmVarDecl>(Decl)) {
if (Decl->getName().empty())
Type += Defn->getName();
Expand All @@ -59,7 +75,8 @@ void DeclRewriter::buildItypeDecl(PVConstraint *Defn, DeclaratorDecl *Decl,
}

IType = " : itype(";
if (ItypesForExtern && Defn->isTypedef()) {

if (IsTypedefVarUnchecked) {
// In -itypes-for-extern mode we do not rewrite typedefs to checked types.
// They are given a checked itype instead. The unchecked portion of the
// itype continues to use the original typedef, but the typedef in the
Expand Down
20 changes: 11 additions & 9 deletions clang/lib/3C/ProgramInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -640,8 +640,10 @@ void ProgramInfo::addVariable(clang::DeclaratorDecl *D,
NewCV = F;

auto RetTy = FD->getReturnType();
unifyIfTypedef(RetTy.getTypePtr(), *AstContext, FD, F->getExternalReturn());
unifyIfTypedef(RetTy.getTypePtr(), *AstContext, FD, F->getInternalReturn());
unifyIfTypedef(RetTy.getTypePtr(), *AstContext, F->getExternalReturn(),
Wild_to_Safe);
unifyIfTypedef(RetTy.getTypePtr(), *AstContext, F->getInternalReturn(),
Safe_to_Wild);
ensureNtCorrect(RetTy, *AstContext, F->getExternalReturn());
ensureNtCorrect(RetTy, *AstContext, F->getInternalReturn());

Expand All @@ -652,8 +654,8 @@ void ProgramInfo::addVariable(clang::DeclaratorDecl *D,
const Type *Ty = PVD->getType().getTypePtr();
PVConstraint *PVInternal = F->getInternalParam(I);
PVConstraint *PVExternal = F->getExternalParam(I);
unifyIfTypedef(Ty, *AstContext, PVD, PVInternal);
unifyIfTypedef(Ty, *AstContext, PVD, PVExternal);
unifyIfTypedef(Ty, *AstContext, PVExternal, Wild_to_Safe);
unifyIfTypedef(Ty, *AstContext, PVInternal, Safe_to_Wild);
ensureNtCorrect(PVD->getType(), *AstContext, PVInternal);
ensureNtCorrect(PVD->getType(), *AstContext, PVExternal);
PVInternal->setValidDecl();
Expand Down Expand Up @@ -681,7 +683,7 @@ void ProgramInfo::addVariable(clang::DeclaratorDecl *D,
P->setValidDecl();
NewCV = P;
std::string VarName(VD->getName());
unifyIfTypedef(Ty, *AstContext, VD, P);
unifyIfTypedef(Ty, *AstContext, P);
ensureNtCorrect(VD->getType(), *AstContext, P);
if (VD->hasGlobalStorage()) {
// If we see a definition for this global variable, indicate so in
Expand All @@ -702,7 +704,7 @@ void ProgramInfo::addVariable(clang::DeclaratorDecl *D,
const Type *Ty = FlD->getTypeSourceInfo()->getTypeLoc().getTypePtr();
if (Ty->isPointerType() || Ty->isArrayType()) {
PVConstraint *P = new PVConstraint(D, *this, *AstContext);
unifyIfTypedef(Ty, *AstContext, FlD, P);
unifyIfTypedef(Ty, *AstContext, P);
NewCV = P;
NewCV->setValidDecl();
}
Expand All @@ -726,15 +728,15 @@ void ProgramInfo::ensureNtCorrect(const QualType &QT, const ASTContext &C,
}

void ProgramInfo::unifyIfTypedef(const Type *Ty, ASTContext &Context,
DeclaratorDecl *Decl, PVConstraint *P) {
PVConstraint *P, ConsAction CA) {
if (const auto *TDT = dyn_cast<TypedefType>(Ty)) {
auto *TDecl = TDT->getDecl();
auto PSL = PersistentSourceLoc::mkPSL(TDecl, Context);
auto O = lookupTypedef(PSL);
if (O.hasValue()) {
auto *Bounds = &O.getValue();
P->setTypedef(TDecl, TDecl->getNameAsString());
constrainConsVarGeq(P, Bounds, CS, &PSL, Same_to_Same, true, this);
P->setTypedef(Bounds, TDecl->getNameAsString());
constrainConsVarGeq(P, Bounds, CS, &PSL, CA, false, this);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/3C/basic_checks.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ void mut_pa(PA p) {
p->a = 0;
p->b = 1;
}
//CHECK: void mut_pa(PA p) {
//CHECK: void mut_pa(PA p : itype(_Ptr<struct _A>)) {

void pa_driver(void) {
A a = {0};
Expand Down
120 changes: 120 additions & 0 deletions clang/test/3C/itype_typedef.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// RUN: rm -rf %t*
// RUN: 3c -base-dir=%S -alltypes -addcr %s -- | FileCheck -match-full-lines -check-prefixes="CHECK_ALL","CHECK" %s
// RUN: 3c -base-dir=%S -addcr %s -- | FileCheck -match-full-lines -check-prefixes="CHECK_NOALL","CHECK" %s
// RUN: 3c -base-dir=%S -addcr %s -- | %clang -c -fcheckedc-extension -x c -o /dev/null -
// RUN: 3c -base-dir=%S -alltypes -output-dir=%t.checked %s --
// RUN: 3c -base-dir=%t.checked -alltypes %t.checked/itype_typedef.c -- | diff %t.checked/itype_typedef.c -

// Itype typedef on the paramter

typedef int *td0;
void test0(td0 a) {
//CHECK: typedef _Ptr<int> td0;
//CHECK: void test0(int *a : itype(td0)) {
a = 1;
}

typedef int *td1;
void test1(td1 a) {
//CHECK: typedef int *td1;
//CHECK: void test1(td1 a : itype(_Ptr<int>)) {
td1 b = a;
b = 1;
}

typedef int *td2;
void test2(td2 a) {
//CHECK: typedef int *td2;
//CHECK: void test2(td2 a : itype(_Ptr<int>)) {
td2 b = 1;
}

// Itype typedef on the return

typedef int *td3;
td3 test3() {
//CHECK: typedef _Ptr<int> td3;
//CHECK: int * test3(void) : itype(td3) {
return (int*) 1;
}

typedef int *td4;
td4 test4() {
//CHECK: typedef int *td4;
//CHECK: td4 test4(void) : itype(_Ptr<int>) {
td4 a = 1;
return a;
}

// Itype typedef with array bounds

typedef int *td5;
void test5(td5 a, int n) {
//CHECK: typedef int *td5;
//CHECK_ALL: void test5(td5 a : itype(_Array_ptr<int>) count(n), int n) {
//CHECK_NOALL: void test5(td5 a : itype(_Ptr<int>), int n) {
for (int i = 0; i < n; i++)
a[i];
td5 b = 1;
}

typedef int *td6;
void test6(td6 a, int n) {
//CHECK_ALL: typedef _Array_ptr<int> td6;
//CHECK_ALL: void test6(int *a : itype(td6) count(n), int n) {
//CHECK_NOALL: typedef _Ptr<int> td6;
//CHECK_NOALL: void test6(int *a : itype(td6), int n) {
for (int i = 0; i < n; i++)
a[i];
a = 1;
}

// Itype typedef with type qualifiers

typedef int *td7;
void test7(const td7 a) {
//CHECK: typedef _Ptr<int> td7;
//CHECK: void test7(int *const a : itype(const td7)) {
int *b = a;
b = 1;
}

typedef int *td8;
void test8(const td8 a) {
//CHECK: typedef int *td8;
//CHECK: void test8(const td8 a : itype(const _Ptr<int>)) {
td8 b = a;
b = 1;
}

typedef const int *td9;
void test9(td9 a) {
//CHECK: typedef _Ptr<const int> td9;
//CHECK: void test9(const int *a : itype(td9)) {
int *b = a;
b = 1;
}

typedef const int *td10;
void test10(td10 a) {
//CHECK: typedef const int *td10;
//CHECK: void test10(td10 a : itype(_Ptr<const int>)) {
td10 b = a;
b = 1;
}

// With functions pointers

typedef int (*fp_td0)(int);
void fp_test0(fp_td0 a) {
//CHECK: typedef _Ptr<int (int)> fp_td0;
//CHECK: void fp_test0(int ((*a)(int)) : itype(fp_td0)) {
a = 1;
}

typedef int (*fp_td1)(int);
void fp_test1(fp_td1 a) {
//CHECK: typedef int (*fp_td1)(int);
//CHECK: void fp_test1(fp_td1 a : itype(_Ptr<int (int)>)) {
fp_td1 b = 1;
}