aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-02-25 16:33:18 +0000
committerDouglas Gregor <dgregor@apple.com>2009-02-25 16:33:18 +0000
commit2224f84658fb9b3725a31f2680edb64ae73bf705 (patch)
treed8b3f0a9bfc05c8565e35df1c47b5cc649377136
parent70f2a0485dd81e6684553eb5537a27db4176ed45 (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.cpp3
-rw-r--r--include/clang/AST/Decl.h13
-rw-r--r--lib/AST/Decl.cpp8
-rw-r--r--lib/Sema/SemaDecl.cpp8
-rw-r--r--lib/Sema/SemaExpr.cpp13
-rw-r--r--lib/Sema/SemaExprCXX.cpp2
-rw-r--r--test/Sema/arg-duplicate.c2
-rw-r--r--test/Sema/knr-def-call.c14
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