forked from OSchip/llvm-project
C99 DR #316 implies that the function parameter types that are known
only from a function definition (that does not have a prototype) are only used to determine the compatible with other declarations of that same function. In particular, when referencing the function we pretend as if it does not have a prototype. Implement this behavior, which fixes PR3626. llvm-svn: 65460
This commit is contained in:
parent
5d9cc1763b
commit
739ef0c183
|
@ -4063,7 +4063,8 @@ FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(const char *name) {
|
|||
IdentifierInfo *ID = &Context->Idents.get(name);
|
||||
QualType FType = Context->getFunctionTypeNoProto(Context->VoidPtrTy);
|
||||
return FunctionDecl::Create(*Context, TUDecl,SourceLocation(),
|
||||
ID, FType, FunctionDecl::Extern, false);
|
||||
ID, FType, FunctionDecl::Extern, false,
|
||||
false);
|
||||
}
|
||||
|
||||
Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
|
||||
|
|
|
@ -532,6 +532,7 @@ private:
|
|||
bool IsVirtual : 1;
|
||||
bool IsPure : 1;
|
||||
bool InheritedPrototype : 1;
|
||||
bool HasPrototype : 1;
|
||||
bool IsDeleted : 1;
|
||||
|
||||
// Move to DeclGroup when it is implemented.
|
||||
|
@ -545,7 +546,8 @@ protected:
|
|||
DeclContext(DK),
|
||||
ParamInfo(0), Body(0), PreviousDeclaration(0),
|
||||
SClass(S), IsInline(isInline), IsVirtual(false), IsPure(false),
|
||||
InheritedPrototype(false), IsDeleted(false), TypeSpecStartLoc(TSSL) {}
|
||||
InheritedPrototype(false), HasPrototype(true), IsDeleted(false),
|
||||
TypeSpecStartLoc(TSSL) {}
|
||||
|
||||
virtual ~FunctionDecl() {}
|
||||
virtual void Destroy(ASTContext& C);
|
||||
|
@ -554,6 +556,7 @@ public:
|
|||
static FunctionDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
|
||||
DeclarationName N, QualType T,
|
||||
StorageClass S = None, bool isInline = false,
|
||||
bool hasPrototype = true,
|
||||
SourceLocation TSStartLoc = SourceLocation());
|
||||
|
||||
SourceLocation getTypeSpecStartLoc() const { return TypeSpecStartLoc; }
|
||||
|
@ -588,9 +591,15 @@ public:
|
|||
bool isPure() { return IsPure; }
|
||||
void setPure() { IsPure = true; }
|
||||
|
||||
/// \brief Whether this function has a prototype, either because one
|
||||
/// was explicitly written or because it was "inherited" by merging
|
||||
/// a declaration without a prototype with a declaration that has a
|
||||
/// prototype.
|
||||
bool hasPrototype() const { return HasPrototype || InheritedPrototype; }
|
||||
|
||||
/// \brief Whether this function inherited its prototype from a
|
||||
/// previous declaration.
|
||||
bool inheritedPrototype() { return InheritedPrototype; }
|
||||
bool inheritedPrototype() const { return InheritedPrototype; }
|
||||
void setInheritedPrototype() { InheritedPrototype = true; }
|
||||
|
||||
/// \brief Whether this function has been deleted.
|
||||
|
|
|
@ -75,9 +75,13 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
|
|||
SourceLocation L,
|
||||
DeclarationName N, QualType T,
|
||||
StorageClass S, bool isInline,
|
||||
bool hasPrototype,
|
||||
SourceLocation TypeSpecStartLoc) {
|
||||
return new (C) FunctionDecl(Function, DC, L, N, T, S, isInline,
|
||||
TypeSpecStartLoc);
|
||||
FunctionDecl *New
|
||||
= new (C) FunctionDecl(Function, DC, L, N, T, S, isInline,
|
||||
TypeSpecStartLoc);
|
||||
New->HasPrototype = hasPrototype;
|
||||
return New;
|
||||
}
|
||||
|
||||
BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
|
||||
|
|
|
@ -334,7 +334,8 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
|
|||
FunctionDecl *New = FunctionDecl::Create(Context,
|
||||
Context.getTranslationUnitDecl(),
|
||||
Loc, II, R,
|
||||
FunctionDecl::Extern, false);
|
||||
FunctionDecl::Extern, false,
|
||||
/*hasPrototype=*/true);
|
||||
New->setImplicit();
|
||||
|
||||
// Create Decl objects for each parameter, adding them to the
|
||||
|
@ -1736,6 +1737,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
|||
// code path.
|
||||
NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(),
|
||||
Name, R, SC, isInline,
|
||||
/*hasPrototype=*/true,
|
||||
// FIXME: Move to DeclGroup...
|
||||
D.getDeclSpec().getSourceRange().getBegin());
|
||||
InvalidDecl = true;
|
||||
|
@ -1765,6 +1767,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
|||
NewFD = FunctionDecl::Create(Context, DC,
|
||||
D.getIdentifierLoc(),
|
||||
Name, R, SC, isInline,
|
||||
/*hasPrototype=*/
|
||||
(getLangOptions().CPlusPlus ||
|
||||
(D.getNumTypeObjects() &&
|
||||
D.getTypeObject(0).Fun.hasPrototype)),
|
||||
// FIXME: Move to DeclGroup...
|
||||
D.getDeclSpec().getSourceRange().getBegin());
|
||||
}
|
||||
|
|
|
@ -873,6 +873,19 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
|||
CheckS = CheckS->getParent();
|
||||
}
|
||||
}
|
||||
} else if (FunctionDecl *Func = dyn_cast<FunctionDecl>(VD)) {
|
||||
if (!getLangOptions().CPlusPlus && !Func->hasPrototype()) {
|
||||
// C99 DR 316 says that, if a function type comes from a
|
||||
// function definition (without a prototype), that type is only
|
||||
// used for checking compatibility. Therefore, when referencing
|
||||
// the function, we pretend that we don't have the full function
|
||||
// type.
|
||||
QualType T = Func->getType();
|
||||
QualType NoProtoType = T;
|
||||
if (const FunctionTypeProto *Proto = T->getAsFunctionTypeProto())
|
||||
NoProtoType = Context.getFunctionTypeNoProto(Proto->getResultType());
|
||||
return Owned(BuildDeclRefExpr(VD, NoProtoType, Loc, false, false, SS));
|
||||
}
|
||||
}
|
||||
|
||||
// Only create DeclRefExpr's for valid Decl's.
|
||||
|
|
|
@ -543,7 +543,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
|
|||
QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0);
|
||||
FunctionDecl *Alloc =
|
||||
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
|
||||
FnType, FunctionDecl::None, false,
|
||||
FnType, FunctionDecl::None, false, true,
|
||||
SourceLocation());
|
||||
Alloc->setImplicit();
|
||||
ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
|
||||
|
|
|
@ -9,6 +9,6 @@ int f3(y, x,
|
|||
}
|
||||
|
||||
void f4(void) {
|
||||
f3 (1, 1, 2, 3, 4); // expected-error {{too many arguments to function}}
|
||||
f3 (1, 1, 2, 3, 4);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// RUN: clang -fsyntax-only -verify %s
|
||||
|
||||
// C DR #316, PR 3626.
|
||||
void f0(a, b, c, d) int a,b,c,d; {}
|
||||
void t0(void) { f0(1); }
|
||||
|
||||
void f1(a, b) int a, b; {}
|
||||
void t1(void) { f1(1, 2, 3); }
|
||||
|
||||
void f2(float); // expected-note{{previous declaration is here}}
|
||||
void f2(x) float x; { } // expected-error{{conflicting types for 'f2'}}
|
||||
|
||||
typedef void (*f3)(void);
|
||||
f3 t3(int b) { return b? f0 : f1; } // okay
|
Loading…
Reference in New Issue