Allow redefinitions of extern inline functions in GNU89 mode, just as GCC
does. Fixes PR5253. llvm-svn: 96553
This commit is contained in:
parent
84c51c3581
commit
fea4845609
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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'}}
|
||||
|
||||
|
|
Loading…
Reference in New Issue