@@ -539,13 +539,13 @@ bool FunctionDeclBuilder::VisitFunctionDecl(FunctionDecl *FD) {
539
539
if (!Defnc->hasBody ())
540
540
return true ;
541
541
542
- // DidAnyParams tracks if we have made any changes to the parameters for this
543
- // declarations. If no changes are made, then there is no need to rewrite the
544
- // parameter declarations. This will also be set to true if an itype is added
545
- // to the return, since return itypes are inserted afters params.
542
+ // RewriteParams and RewriteReturn track if we will need to rewrite the
543
+ // parameter and return type declarations on this function. They are first
544
+ // set to true if any changes are made to the types of the parameter and
545
+ // return. If a type has changed, then it must be rewritten. There are then
546
+ // some special circumstances which require rewriting the parameter or return
547
+ // even when the type as not changed.
546
548
bool RewriteParams = false ;
547
- // Does the same job as RewriteParams, but with respect to the return value.
548
- // If the return does not change, there is no need to rewrite it.
549
549
bool RewriteReturn = false ;
550
550
551
551
// Get rewritten parameter variable declarations
@@ -574,12 +574,27 @@ bool FunctionDeclBuilder::VisitFunctionDecl(FunctionDecl *FD) {
574
574
ReturnVar, ItypeStr, RewriteParams, RewriteReturn);
575
575
576
576
// If the return is a function pointer, we need to rewrite the whole
577
- // declaration even if no actual changes were made to the parameters. It could
578
- // probably be done better, but getting the correct source locations is
579
- // painful.
577
+ // declaration even if no actual changes were made to the parameters because
578
+ // the parameter for the function pointer type appear later in the source than
579
+ // the parameters for the function declaration. It could probably be done
580
+ // better, but getting the correct source locations is painful.
580
581
if (FD->getReturnType ()->isFunctionPointerType () && RewriteReturn)
581
582
RewriteParams = true ;
582
583
584
+ // If the function is declared using a typedef for the function type, then we
585
+ // need to rewrite parameters and the return if either would have been
586
+ // rewritten. What this does is expand the typedef to the full function type
587
+ // to avoid the problem of rewriting inside the typedef.
588
+ // FIXME: If issue #437 is fixed in way that preserves typedefs on function
589
+ // declarations, then this conditional should be removed to enable
590
+ // separate rewriting of return type and parameters on the
591
+ // corresponding definition.
592
+ // https://github.com/correctcomputation/checkedc-clang/issues/437
593
+ if ((RewriteReturn || RewriteParams) && hasDeclWithTypedef (FD)) {
594
+ RewriteParams = true ;
595
+ RewriteReturn = true ;
596
+ }
597
+
583
598
// Combine parameter and return variables rewritings into a single rewriting
584
599
// for the entire function declaration.
585
600
std::string NewSig = " " ;
@@ -647,6 +662,10 @@ void FunctionDeclBuilder::buildItypeDecl(PVConstraint *Defn,
647
662
return ;
648
663
}
649
664
665
+ // Note: For a parameter, Type + IType will give the full declaration (including
666
+ // the name) but the breakdown between Type and IType is not guaranteed. For a
667
+ // return, Type will be what goes before the name and IType will be what goes
668
+ // after the parentheses.
650
669
void
651
670
FunctionDeclBuilder::buildDeclVar (PVConstraint *IntCV, PVConstraint *ExtCV,
652
671
DeclaratorDecl *Decl, std::string &Type,
@@ -668,16 +687,34 @@ FunctionDeclBuilder::buildDeclVar(PVConstraint *IntCV, PVConstraint *ExtCV,
668
687
buildItypeDecl (ExtCV, Decl, Type, IType, RewriteParm, RewriteRet);
669
688
return ;
670
689
}
671
- // Variables that do not need to be rewritten fall through to here. Type
672
- // strings are taken unchanged from the original source.
673
- if (isa<ParmVarDecl>(Decl)) {
674
- Type = getSourceText (Decl->getSourceRange (), *Context);
675
- IType = " " ;
690
+ // Variables that do not need to be rewritten fall through to here.
691
+ // For parameter variables, we try to extract the declaration from the source
692
+ // code. This preserves macros and other formatting. This isn't possible for
693
+ // return variables because the itype on returns is located after the
694
+ // parameter list. Sometimes we cannot get the original source for a parameter
695
+ // declaration, for example if a function prototype is declared using a
696
+ // typedef or the parameter declaration is inside a macro. For these cases, we
697
+ // just fall back to reconstructing the declaration from the PVConstraint.
698
+ ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(Decl);
699
+ if (PVD) {
700
+ SourceRange Range = PVD->getSourceRange ();
701
+ if (Range.isValid ()) {
702
+ Type = getSourceText (Range, *Context);
703
+ if (!Type.empty ()) {
704
+ // Great, we got the original source including any itype and bounds.
705
+ IType = " " ;
706
+ return ;
707
+ }
708
+ }
709
+ // Otherwise, reconstruct the name and type, and reuse the code below for
710
+ // the itype and bounds.
711
+ // TODO: Do we care about `register` or anything else this doesn't handle?
712
+ Type = qtyToStr (PVD->getOriginalType (), PVD->getNameAsString ());
676
713
} else {
677
714
Type = ExtCV->getOriginalTy () + " " ;
678
- IType = getExistingIType (ExtCV);
679
- IType += ABRewriter.getBoundsString (ExtCV, Decl, !IType.empty ());
680
715
}
716
+ IType = getExistingIType (ExtCV);
717
+ IType += ABRewriter.getBoundsString (ExtCV, Decl, !IType.empty ());
681
718
}
682
719
683
720
std::string FunctionDeclBuilder::getExistingIType (ConstraintVariable *DeclC) {
@@ -692,6 +729,37 @@ bool FunctionDeclBuilder::isFunctionVisited(std::string FuncName) {
692
729
return VisitedSet.find (FuncName) != VisitedSet.end ();
693
730
}
694
731
732
+ // Given a function declaration figure out if this declaration or any other
733
+ // declaration of the same function is declared using a typedefed function type.
734
+ bool FunctionDeclBuilder::hasDeclWithTypedef (const FunctionDecl *FD) {
735
+ for (FunctionDecl *FDIter : FD->redecls ()) {
736
+ // If the declaration type is TypedefType, then this is definitely declared
737
+ // using a typedef. This only happens when the typedefed declaration is the
738
+ // first declaration of a function.
739
+ if (isa_and_nonnull<TypedefType>(FDIter->getType ().getTypePtrOrNull ()))
740
+ return true ;
741
+ // Next look for a TypeDefTypeLoc. This is present on the typedefed
742
+ // declaration even when it is not the first declaration.
743
+ TypeSourceInfo *TSI = FDIter->getTypeSourceInfo ();
744
+ if (TSI) {
745
+ if (!TSI->getTypeLoc ().getAs <TypedefTypeLoc>().isNull ())
746
+ return true ;
747
+ } else {
748
+ // This still could possibly be a typedef type if TSI was NULL.
749
+ // TypeSourceInfo is null for implicit function declarations, so if a
750
+ // implicit declaration uses a typedef, it will be missed. That's fine
751
+ // since an implicit declaration can't be rewritten anyways.
752
+ // There might be other ways it can be null that I'm not aware of.
753
+ if (Verbose) {
754
+ llvm::errs () << " Unable to conclusively determine if a function "
755
+ << " declaration uses a typedef.\n " ;
756
+ FDIter->dump ();
757
+ }
758
+ }
759
+ }
760
+ return false ;
761
+ }
762
+
695
763
bool FieldFinder::VisitFieldDecl (FieldDecl *FD) {
696
764
GVG.addGlobalDecl (FD);
697
765
return true ;
0 commit comments