diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-02-16 18:20:44 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-02-16 18:20:44 +0000 |
commit | 6871981fbccba9e8a63997d58245ec0add114f49 (patch) | |
tree | 7626e9c24e0b70c4e4285c1678b1b2d21dfb99ec | |
parent | 83d67909f9058816d1ab49910708c0ba3c4c8096 (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.h | 8 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 17 | ||||
-rw-r--r-- | test/Sema/function-redecl.c | 30 |
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; +} |