diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/AST/Decl.h | 8 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 17 | ||||
-rw-r--r-- | clang/test/Sema/function-redecl.c | 30 |
3 files changed, 54 insertions, 1 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 337f041b478..18a56cf8922 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 3960a7d57c0..444f85e7739 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/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/clang/test/Sema/function-redecl.c b/clang/test/Sema/function-redecl.c new file mode 100644 index 00000000000..85663396cf3 --- /dev/null +++ b/clang/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; +} |