diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-02-25 16:33:18 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-02-25 16:33:18 +0000 |
commit | 2224f84658fb9b3725a31f2680edb64ae73bf705 (patch) | |
tree | d8b3f0a9bfc05c8565e35df1c47b5cc649377136 | |
parent | 70f2a0485dd81e6684553eb5537a27db4176ed45 (diff) |
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65460 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | Driver/RewriteObjC.cpp | 3 | ||||
-rw-r--r-- | include/clang/AST/Decl.h | 13 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 2 | ||||
-rw-r--r-- | test/Sema/arg-duplicate.c | 2 | ||||
-rw-r--r-- | test/Sema/knr-def-call.c | 14 |
8 files changed, 55 insertions, 8 deletions
diff --git a/Driver/RewriteObjC.cpp b/Driver/RewriteObjC.cpp index 610e1c5106..bd95a3922a 100644 --- a/Driver/RewriteObjC.cpp +++ b/Driver/RewriteObjC.cpp @@ -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) { diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index a8bd4b8211..aa009c8b4c 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -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. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 9bf35ee83d..2732bf93c1 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -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) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index abb5e40dd4..c312195972 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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()); } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 174e408ead..98d6b12b9c 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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. diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index ea59b644c9..c8671bc2e3 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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(), diff --git a/test/Sema/arg-duplicate.c b/test/Sema/arg-duplicate.c index 81cb8fd9c2..c5498a2309 100644 --- a/test/Sema/arg-duplicate.c +++ b/test/Sema/arg-duplicate.c @@ -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); } diff --git a/test/Sema/knr-def-call.c b/test/Sema/knr-def-call.c new file mode 100644 index 0000000000..706f21418e --- /dev/null +++ b/test/Sema/knr-def-call.c @@ -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 |