Allow redefinitions of extern inline functions in GNU89 mode, just as GCC

does. Fixes PR5253.

llvm-svn: 96553
This commit is contained in:
Charles Davis 2010-02-18 02:00:42 +00:00
parent 84c51c3581
commit fea4845609
3 changed files with 60 additions and 3 deletions

View File

@ -908,6 +908,16 @@ static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx,
return Sema::CXXCopyAssignment;
}
/// canREdefineFunction - checks if a function can be redefined. Currently,
/// only extern inline functions can be redefined, and even then only in
/// GNU89 mode.
static bool canRedefineFunction(const FunctionDecl *FD,
const LangOptions& LangOpts) {
return (LangOpts.GNUMode && !LangOpts.C99 && !LangOpts.CPlusPlus &&
FD->isInlineSpecified() &&
FD->getStorageClass() == FunctionDecl::Extern);
}
/// MergeFunctionDecl - We just parsed a function 'New' from
/// declarator D which has the same name and scope as a previous
/// declaration 'Old'. Figure out how to resolve this situation,
@ -956,9 +966,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
QualType OldQType = Context.getCanonicalType(Old->getType());
QualType NewQType = Context.getCanonicalType(New->getType());
// Don't complain about this if we're in GNU89 mode and the old function
// is an extern inline function.
if (!isa<CXXMethodDecl>(New) && !isa<CXXMethodDecl>(Old) &&
New->getStorageClass() == FunctionDecl::Static &&
Old->getStorageClass() != FunctionDecl::Static) {
Old->getStorageClass() != FunctionDecl::Static &&
!canRedefineFunction(Old, getLangOptions())) {
Diag(New->getLocation(), diag::err_static_non_static)
<< New;
Diag(Old->getLocation(), PrevDiag);
@ -4062,8 +4075,11 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
CurFunctionNeedsScopeChecking = false;
// See if this is a redefinition.
// But don't complain if we're in GNU89 mode and the previous definition
// was an extern inline function.
const FunctionDecl *Definition;
if (FD->getBody(Definition)) {
if (FD->getBody(Definition) &&
!canRedefineFunction(Definition, getLangOptions())) {
Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName();
Diag(Definition->getLocation(), diag::note_previous_definition);
}

View File

@ -0,0 +1,25 @@
// RUN: %clang -S -emit-llvm -std=gnu89 -o - %s | FileCheck %s
// PR5253
// If an extern inline function is redefined, functions should call the
// redefinition.
extern inline int f(int a) {return a;}
int g(void) {return f(0);}
// CHECK: call i32 @f
int f(int b) {return 1+b;}
// CHECK: load i32* %{{.*}}
// CHECK: add nsw i32 1, %{{.*}}
int h(void) {return f(1);}
// CHECK: call i32 @f
// It shouldn't matter if the function was redefined static.
extern inline int f2(int a, int b) {return a+b;}
int g2(void) {return f2(0,1);}
// CHECK: call i32 @f2
static int f2(int a, int b) {return a*b;}
// CHECK: load i32* %{{.*}}
// CHECK: load i32* %{{.*}}
// CHECK: mul i32 %{{.*}}, %{{.*}}
int h2(void) {return f2(1,2);}
// CHECK: call i32 @f2

View File

@ -1,6 +1,22 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -std=gnu89 -fsyntax-only -verify %s
// Check that we don't allow illegal uses of inline
inline int a; // expected-error{{'inline' can only appear on functions}}
typedef inline int b; // expected-error{{'inline' can only appear on functions}}
int d(inline int a); // expected-error{{'inline' can only appear on functions}}
// PR5253
// GNU Extension: check that we can redefine an extern inline function
extern inline int f(int a) {return a;}
int f(int b) {return b;} // expected-note{{previous definition is here}}
// And now check that we can't redefine a normal function
int f(int c) {return c;} // expected-error{{redefinition of 'f'}}
// Check that we can redefine an extern inline function as a static function
extern inline int g(int a) {return a;}
static int g(int b) {return b;}
// Check that we ensure the types of the two definitions are the same
extern inline int h(int a) {return a;} // expected-note{{previous definition is here}}
int h(short b) {return b;} // expected-error{{conflicting types for 'h'}}