From f3f8d2a52ebc0acbe6269a0302f90c21668e2404 Mon Sep 17 00:00:00 2001 From: Charles Davis Date: Thu, 18 Feb 2010 02:00:42 +0000 Subject: [PATCH] Allow redefinitions of extern inline functions in GNU89 mode, just as GCC does. Fixes PR5253. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96553 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaDecl.cpp | 20 ++++++++++++++++++-- test/CodeGen/extern-inline.c | 25 +++++++++++++++++++++++++ test/Sema/inline.c | 18 +++++++++++++++++- 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 test/CodeGen/extern-inline.c diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index e7217dc220..949669aa57 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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(New) && !isa(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); } diff --git a/test/CodeGen/extern-inline.c b/test/CodeGen/extern-inline.c new file mode 100644 index 0000000000..5dd9bfda57 --- /dev/null +++ b/test/CodeGen/extern-inline.c @@ -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 + diff --git a/test/Sema/inline.c b/test/Sema/inline.c index 3c99f24337..b4795d3d93 100644 --- a/test/Sema/inline.c +++ b/test/Sema/inline.c @@ -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'}} + -- 2.40.0