Skip to content

Commit 785f962

Browse files
Handle function declaration appearing after definition (fix #399) (#411)
Ensure that constrains generated due to a function's declaration are applied to the variables generated at the definition even when declaration appears after the definition. This is done by copying the atoms from the definition constraint variable into the declaration constraint variable using brainTransplant before any constraints are added on the declaration. Also change insertNewFVConstraint to return void. Previously, it returned a bool, but the value was never used. This also applies to two functions that are only ever called from inside insertNewFVConstraint.
1 parent 48b6d9f commit 785f962

File tree

3 files changed

+84
-42
lines changed

3 files changed

+84
-42
lines changed

clang/include/clang/3C/ProgramInfo.h

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -169,15 +169,13 @@ class ProgramInfo : public ProgramVariableAdder {
169169
TypeParamBindingsT TypeParamBindings;
170170

171171
// Insert the given FVConstraint* set into the provided Map.
172-
// Returns true if successful else false.
173-
bool insertIntoExternalFunctionMap(ExternalFunctionMapType &Map,
172+
void insertIntoExternalFunctionMap(ExternalFunctionMapType &Map,
174173
const std::string &FuncName,
175-
FVConstraint *ToIns, FunctionDecl *FD,
174+
FVConstraint *NewC, FunctionDecl *FD,
176175
ASTContext *C);
177176

178177
// Inserts the given FVConstraint* set into the provided static map.
179-
// Returns true if successful else false.
180-
bool insertIntoStaticFunctionMap(StaticFunctionMapType &Map,
178+
void insertIntoStaticFunctionMap(StaticFunctionMapType &Map,
181179
const std::string &FuncName,
182180
const std::string &FileName,
183181
FVConstraint *ToIns, FunctionDecl *FD,
@@ -188,9 +186,14 @@ class ProgramInfo : public ProgramVariableAdder {
188186
// * va_list-typed variables
189187
void specialCaseVarIntros(ValueDecl *D, ASTContext *Context);
190188

191-
// Inserts the given FVConstraint* set into the global map, depending
192-
// on whether static or not; returns true on success
193-
bool insertNewFVConstraint(FunctionDecl *FD, FVConstraint *FVCon,
189+
// Inserts the given FVConstraint set into the extern or static function map.
190+
// Note: This can trigger a brainTransplant from an existing FVConstraint into
191+
// the argument FVConstraint. The brainTransplant copies the atoms of the
192+
// existing FVConstraint into the argument. This effectively throws out any
193+
// constraints that may been applied to the argument FVConstraint, so do not
194+
// call this function any time other than immediately after constructing an
195+
// FVConstraint.
196+
void insertNewFVConstraint(FunctionDecl *FD, FVConstraint *FVCon,
194197
ASTContext *C);
195198

196199
// Retrieves a FVConstraint* from a Decl (which could be static, or global)

clang/lib/3C/ProgramInfo.cpp

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -402,23 +402,20 @@ void ProgramInfo::exitCompilationUnit() {
402402
return;
403403
}
404404

405-
bool ProgramInfo::insertIntoExternalFunctionMap(ExternalFunctionMapType &Map,
405+
void ProgramInfo::insertIntoExternalFunctionMap(ExternalFunctionMapType &Map,
406406
const std::string &FuncName,
407407
FVConstraint *NewC,
408408
FunctionDecl *FD,
409409
ASTContext *C) {
410-
bool RetVal = false;
411410
if (Map.find(FuncName) == Map.end()) {
412411
Map[FuncName] = NewC;
413-
RetVal = true;
414412
} else {
415413
auto *OldC = Map[FuncName];
416414
if (!OldC->hasBody()) {
417415
if (NewC->hasBody() ||
418416
(OldC->numParams() == 0 && NewC->numParams() != 0)) {
419417
NewC->brainTransplant(OldC, *this);
420418
Map[FuncName] = NewC;
421-
RetVal = true;
422419
} else {
423420
// if the current FV constraint is not a definition?
424421
// then merge.
@@ -450,44 +447,42 @@ bool ProgramInfo::insertIntoExternalFunctionMap(ExternalFunctionMapType &Map,
450447
DiagnosticsEngine::Fatal, "duplicate definition for function %0");
451448
DE.Report(FD->getLocation(), DuplicateDefinitionsID).AddString(FuncName);
452449
exit(1);
450+
} else {
451+
// The old constraint has a body, but we've encountered another prototype
452+
// for the function.
453+
assert(OldC->hasBody() && !NewC->hasBody());
454+
// By transplanting the atoms of OldC into NewC, we ensure that any
455+
// constraints applied to NewC later on constrain the atoms of OldC.
456+
NewC->brainTransplant(OldC, *this);
453457
}
454-
// else oldc->hasBody() so we can ignore the newC prototype
455458
}
456-
return RetVal;
457459
}
458460

459-
bool ProgramInfo::insertIntoStaticFunctionMap(StaticFunctionMapType &Map,
461+
void ProgramInfo::insertIntoStaticFunctionMap(StaticFunctionMapType &Map,
460462
const std::string &FuncName,
461463
const std::string &FileName,
462464
FVConstraint *ToIns,
463465
FunctionDecl *FD, ASTContext *C) {
464-
bool RetVal = false;
465-
if (Map.find(FileName) == Map.end()) {
466+
if (Map.find(FileName) == Map.end())
466467
Map[FileName][FuncName] = ToIns;
467-
RetVal = true;
468-
} else {
469-
RetVal =
470-
insertIntoExternalFunctionMap(Map[FileName], FuncName, ToIns, FD, C);
471-
}
472-
return RetVal;
468+
else
469+
insertIntoExternalFunctionMap(Map[FileName], FuncName, ToIns, FD, C);
473470
}
474471

475-
bool ProgramInfo::insertNewFVConstraint(FunctionDecl *FD, FVConstraint *FVCon,
472+
void ProgramInfo::insertNewFVConstraint(FunctionDecl *FD, FVConstraint *FVCon,
476473
ASTContext *C) {
477-
bool Ret = false;
478474
std::string FuncName = FD->getNameAsString();
479475
if (FD->isGlobal()) {
480476
// external method.
481-
Ret = insertIntoExternalFunctionMap(ExternalFunctionFVCons, FuncName, FVCon,
482-
FD, C);
477+
insertIntoExternalFunctionMap(ExternalFunctionFVCons, FuncName, FVCon, FD,
478+
C);
483479
} else {
484480
// static method
485481
auto Psl = PersistentSourceLoc::mkPSL(FD, *C);
486482
std::string FuncFileName = Psl.getFileName();
487-
Ret = insertIntoStaticFunctionMap(StaticFunctionFVCons, FuncName,
488-
FuncFileName, FVCon, FD, C);
483+
insertIntoStaticFunctionMap(StaticFunctionFVCons, FuncName, FuncFileName,
484+
FVCon, FD, C);
489485
}
490-
return Ret;
491486
}
492487

493488
void ProgramInfo::specialCaseVarIntros(ValueDecl *D, ASTContext *Context) {
@@ -548,32 +543,39 @@ void ProgramInfo::addVariable(clang::DeclaratorDecl *D,
548543
// Function Decls have FVConstraints.
549544
FVConstraint *F = new FVConstraint(D, *this, *AstContext);
550545
F->setValidDecl();
551-
PVConstraint *RetExternal = F->getExternalReturn();
552-
PVConstraint *RetInternal = F->getInternalReturn();
553-
auto Ret_Ty = FD->getReturnType();
554-
unifyIfTypedef(Ret_Ty.getTypePtr(), *AstContext, FD, RetExternal);
555-
unifyIfTypedef(Ret_Ty.getTypePtr(), *AstContext, FD, RetInternal);
556-
557546

558547
// Handling of PSL collision for functions is different since we need to
559548
// consider the static and extern function maps.
560549
if (Variables.find(PLoc) != Variables.end()) {
561550
// Try to find a previous definition based on function name
562551
if (!getFuncConstraint(FD, AstContext)) {
563-
constrainWildIfMacro(F, FD->getLocation());
552+
// No function with the same name exists. It's concerning that
553+
// something already exists at this source location, but we add the
554+
// function to the function map anyways. The function map indexes by
555+
// function name, so there's no collision.
564556
insertNewFVConstraint(FD, F, AstContext);
557+
constrainWildIfMacro(F, FD->getLocation());
565558
} else {
566-
// FIXME: Visiting same function in same source location twice.
567-
// This shouldn't happen, but it does for some std lib functions
568-
// on our benchmarks programs (vsftpd, lua, etc.). Bailing for
569-
// now, but a real fix will catch and prevent this earlier.
559+
// A function with the same name exists in the same source location.
560+
// This happens when a function is defined in a header file which is
561+
// included in multiple translation units. getFuncConstraint returned
562+
// non-null, so we know that the definition has been processed already,
563+
// and there is no more work to do.
570564
}
571565
return;
572566
}
573567

574-
/* Store the FVConstraint in the global and Variables maps */
568+
// Store the FVConstraint in the global and Variables maps. In doing this,
569+
// insertNewFVConstraint might replace the atoms in F with the atoms of a
570+
// FVConstraint that already exists in the map. Doing this loses any
571+
// constraints that might have effected the original atoms, so do not create
572+
// any constraint on F before this function is called.
575573
insertNewFVConstraint(FD, F, AstContext);
576574

575+
auto RetTy = FD->getReturnType();
576+
unifyIfTypedef(RetTy.getTypePtr(), *AstContext, FD, F->getExternalReturn());
577+
unifyIfTypedef(RetTy.getTypePtr(), *AstContext, FD, F->getInternalReturn());
578+
577579
NewCV = F;
578580
// Add mappings from the parameters PLoc to the constraint variables for
579581
// the parameters.

clang/test/3C/defn_then_decl.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: 3c -alltypes -addcr %s -- | FileCheck -match-full-lines -check-prefixes="CHECK_ALL","CHECK" %s
2+
// RUN: 3c -addcr %s -- | FileCheck -match-full-lines -check-prefixes="CHECK_NOALL","CHECK" %s
3+
// RUN: 3c -alltypes -addcr %s -- | %clang -c -fcheckedc-extension -x c -o /dev/null -
4+
// RUN: 3c -alltypes -output-postfix=checked %s
5+
// RUN: 3c -alltypes %S/defn_then_decl.checked.c -- | count 0
6+
// RUN: rm %S/defn_then_decl.checked.c
7+
8+
// Tests behavior when a function declaration appears after the definition for
9+
// that function. A specific issue that existed caused constraints applied to
10+
// the declaration (for example, when the declaration is in a macro) to not
11+
// be correctly applied to the original definition.
12+
13+
void test0(int *p) {}
14+
#define MYDECL void test0(int *p);
15+
MYDECL
16+
17+
void test1(int *p) {}
18+
//CHECK: void test1(_Ptr<int> p) _Checked {}
19+
void test1(int *p);
20+
//CHECK: void test1(_Ptr<int> p);
21+
22+
void test2(int *p);
23+
//CHECK: void test2(_Ptr<int> p);
24+
void test2(int *p) {}
25+
//CHECK: void test2(_Ptr<int> p) _Checked {}
26+
void test2(int *p);
27+
//CHECK: void test2(_Ptr<int> p);
28+
29+
void test3(int *p) { p = 1; }
30+
//CHECK: void test3(int *p : itype(_Ptr<int>)) { p = 1; }
31+
void test3(int *p);
32+
//CHECK: void test3(int *p : itype(_Ptr<int>));
33+
34+
void test4(int *p) {}
35+
//CHECK: void test4(_Ptr<int> p) _Checked {}
36+
void test4();
37+
//CHECK: void test4(_Ptr<int> p);

0 commit comments

Comments
 (0)