forked from OSchip/llvm-project
Sema: Implement DR317
Summary: Declaring a function as inline after it has been defined is in violation of [dcl.fct.spec]p4. The program would get a strong definition instead of getting a function with linkonce_odr linkage. Reviewers: rsmith CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D3220 llvm-svn: 205129
This commit is contained in:
parent
0dc714a00f
commit
ee4f4025c3
|
@ -3714,6 +3714,8 @@ def warn_redefinition_of_typedef : ExtWarn<
|
||||||
def err_redefinition_variably_modified_typedef : Error<
|
def err_redefinition_variably_modified_typedef : Error<
|
||||||
"redefinition of %select{typedef|type alias}0 for variably-modified type %1">;
|
"redefinition of %select{typedef|type alias}0 for variably-modified type %1">;
|
||||||
|
|
||||||
|
def err_inline_decl_follows_def : Error<
|
||||||
|
"inline declaration of %0 follows non-inline definition">;
|
||||||
def err_inline_declaration_block_scope : Error<
|
def err_inline_declaration_block_scope : Error<
|
||||||
"inline declaration of %0 not allowed in block scope">;
|
"inline declaration of %0 not allowed in block scope">;
|
||||||
def err_static_non_static : Error<
|
def err_static_non_static : Error<
|
||||||
|
|
|
@ -584,6 +584,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const FunctionDecl *Def;
|
||||||
// C++11 [dcl.constexpr]p1: If any declaration of a function or function
|
// C++11 [dcl.constexpr]p1: If any declaration of a function or function
|
||||||
// template has a constexpr specifier then all its declarations shall
|
// template has a constexpr specifier then all its declarations shall
|
||||||
// contain the constexpr specifier.
|
// contain the constexpr specifier.
|
||||||
|
@ -592,6 +593,13 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
|
||||||
<< New << New->isConstexpr();
|
<< New << New->isConstexpr();
|
||||||
Diag(Old->getLocation(), diag::note_previous_declaration);
|
Diag(Old->getLocation(), diag::note_previous_declaration);
|
||||||
Invalid = true;
|
Invalid = true;
|
||||||
|
} else if (!Old->isInlined() && New->isInlined() && Old->isDefined(Def)) {
|
||||||
|
// C++11 [dcl.fcn.spec]p4:
|
||||||
|
// If the definition of a function appears in a translation unit before its
|
||||||
|
// first declaration as inline, the program is ill-formed.
|
||||||
|
Diag(New->getLocation(), diag::err_inline_decl_follows_def) << New;
|
||||||
|
Diag(Def->getLocation(), diag::note_previous_definition);
|
||||||
|
Invalid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// C++11 [dcl.fct.default]p4: If a friend declaration specifies a default
|
// C++11 [dcl.fct.default]p4: If a friend declaration specifies a default
|
||||||
|
|
|
@ -192,9 +192,9 @@ namespace dr314 { // dr314: dup 1710
|
||||||
// dr315: na
|
// dr315: na
|
||||||
// dr316: sup 1004
|
// dr316: sup 1004
|
||||||
|
|
||||||
namespace dr317 { // dr317: no
|
namespace dr317 { // dr317: 3.5
|
||||||
void f() {}
|
void f() {} // expected-note {{previous}}
|
||||||
inline void f(); // FIXME: ill-formed
|
inline void f(); // expected-error {{inline declaration of 'f' follows non-inline definition}}
|
||||||
|
|
||||||
int g();
|
int g();
|
||||||
int n = g();
|
int n = g();
|
||||||
|
@ -202,8 +202,8 @@ namespace dr317 { // dr317: no
|
||||||
|
|
||||||
int h();
|
int h();
|
||||||
int m = h();
|
int m = h();
|
||||||
int h() { return 0; }
|
int h() { return 0; } // expected-note {{previous}}
|
||||||
inline int h(); // FIXME: ill-formed
|
inline int h(); // expected-error {{inline declaration of 'h' follows non-inline definition}}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace dr318 { // dr318: sup 1310
|
namespace dr318 { // dr318: sup 1310
|
||||||
|
|
|
@ -30,7 +30,7 @@ class B {
|
||||||
void f(A *a) { a->f(); }
|
void f(A *a) { a->f(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
void bar() {} // expected-note {{previous definition is here}}
|
inline void bar() {} // expected-note {{previous definition is here}}
|
||||||
class E {
|
class E {
|
||||||
friend void bar() {} // expected-error {{redefinition of 'bar'}}
|
friend void bar() {} // expected-error {{redefinition of 'bar'}}
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,7 +24,7 @@ struct Streamer;
|
||||||
|
|
||||||
typedef struct Foo {} Foo;
|
typedef struct Foo {} Foo;
|
||||||
|
|
||||||
std_ostream& operator << (std_ostream&, const Streamer<Foo>&);
|
inline std_ostream& operator << (std_ostream&, const Streamer<Foo>&);
|
||||||
|
|
||||||
void test(const Streamer<Foo>& foo)
|
void test(const Streamer<Foo>& foo)
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,7 +29,7 @@ struct Streamer
|
||||||
|
|
||||||
typedef struct Foo {} Foo;
|
typedef struct Foo {} Foo;
|
||||||
|
|
||||||
std_ostream& operator << (std_ostream&, const Streamer<Foo>&);
|
inline std_ostream& operator << (std_ostream&, const Streamer<Foo>&);
|
||||||
#ifdef REDEFINE
|
#ifdef REDEFINE
|
||||||
std_ostream& operator << (std_ostream& o, const Streamer<Foo>&) // expected-note{{is here}}
|
std_ostream& operator << (std_ostream& o, const Streamer<Foo>&) // expected-note{{is here}}
|
||||||
{
|
{
|
||||||
|
|
|
@ -1943,7 +1943,7 @@ of class templates</td>
|
||||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#317">317</a></td>
|
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#317">317</a></td>
|
||||||
<td>CD1</td>
|
<td>CD1</td>
|
||||||
<td>Can a function be declared inline after it has been called?</td>
|
<td>Can a function be declared inline after it has been called?</td>
|
||||||
<td class="none" align="center">No</td>
|
<td class="svn" align="center">SVN</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr id="318">
|
<tr id="318">
|
||||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#318">318</a></td>
|
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#318">318</a></td>
|
||||||
|
|
Loading…
Reference in New Issue