aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-02-16 18:20:44 +0000
committerDouglas Gregor <dgregor@apple.com>2009-02-16 18:20:44 +0000
commit6871981fbccba9e8a63997d58245ec0add114f49 (patch)
tree7626e9c24e0b70c4e4285c1678b1b2d21dfb99ec
parent83d67909f9058816d1ab49910708c0ba3c4c8096 (diff)
When a function with a prototype is redeclared without a prototype,
merge the prototype into the redeclaration (and make a note in the declaration). Fixes PR3588. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64641 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/Decl.h8
-rw-r--r--lib/Sema/SemaDecl.cpp17
-rw-r--r--test/Sema/function-redecl.c30
3 files changed, 54 insertions, 1 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 337f041b47..18a56cf892 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -535,6 +535,7 @@ private:
bool IsInline : 1;
bool IsVirtual : 1;
bool IsPure : 1;
+ bool InheritedPrototype : 1;
// Move to DeclGroup when it is implemented.
SourceLocation TypeSpecStartLoc;
@@ -547,7 +548,7 @@ protected:
DeclContext(DK),
ParamInfo(0), Body(0), PreviousDeclaration(0),
SClass(S), IsInline(isInline), IsVirtual(false), IsPure(false),
- TypeSpecStartLoc(TSSL) {}
+ InheritedPrototype(false), TypeSpecStartLoc(TSSL) {}
virtual ~FunctionDecl() {}
virtual void Destroy(ASTContext& C);
@@ -590,6 +591,11 @@ public:
bool isPure() { return IsPure; }
void setPure() { IsPure = true; }
+ /// \brief Whether this function inherited its prototype from a
+ /// previous declaration.
+ bool inheritedPrototype() { return InheritedPrototype; }
+ void setInheritedPrototype() { InheritedPrototype = true; }
+
/// getPreviousDeclaration - Return the previous declaration of this
/// function.
const FunctionDecl *getPreviousDeclaration() const {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 3960a7d57c..444f85e773 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -593,7 +593,24 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
// duplicate function decls like "void f(int); void f(enum X);" properly.
if (!getLangOptions().CPlusPlus &&
Context.typesAreCompatible(OldQType, NewQType)) {
+ const FunctionType *NewFuncType = NewQType->getAsFunctionType();
+ const FunctionTypeProto *OldProto = 0;
+ if (isa<FunctionTypeNoProto>(NewFuncType) &&
+ (OldProto = OldQType->getAsFunctionTypeProto())) {
+ // The old declaration provided a function prototype, but the
+ // new declaration does not. Merge in the prototype.
+ llvm::SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(),
+ OldProto->arg_type_end());
+ NewQType = Context.getFunctionType(NewFuncType->getResultType(),
+ &ParamTypes[0], ParamTypes.size(),
+ OldProto->isVariadic(),
+ OldProto->getTypeQuals());
+ New->setType(NewQType);
+ New->setInheritedPrototype();
+ }
+
MergeAttributes(New, Old);
+
return false;
}
diff --git a/test/Sema/function-redecl.c b/test/Sema/function-redecl.c
new file mode 100644
index 0000000000..85663396cf
--- /dev/null
+++ b/test/Sema/function-redecl.c
@@ -0,0 +1,30 @@
+// RUN: clang -fsyntax-only -verify %s
+
+// PR3588
+void g0(int, int);
+void g0(); // expected-note{{previous declaration is here}}
+
+void f0() {
+ g0(1, 2, 3); // expected-error{{too many arguments to function call}}
+}
+
+void g0(int); // expected-error{{conflicting types for 'g0'}}
+
+int g1(int, int);
+
+typedef int INT;
+
+INT g1(x, y)
+ int x;
+ int y;
+{
+ return x + y;
+}
+
+int g2(int, int); // expected-note{{previous declaration is here}}
+
+INT g2(x) // expected-error{{conflicting types for 'g2'}}
+ int x;
+{
+ return x;
+}