Skip to content

Commit 4e37891

Browse files
committed
PR34163: Don't cache an incorrect key function for a class if queried between
the class becoming complete and its inline methods being parsed. This replaces the hack of using the "late parsed template" flag to track member functions with bodies we've not parsed yet; instead we now use the "will have body" flag, which carries the desired implication that the function declaration *is* a definition, and that we've just not parsed its body yet. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@310776 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 1b599a5 commit 4e37891

File tree

8 files changed

+33
-30
lines changed

8 files changed

+33
-30
lines changed

include/clang/AST/Decl.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -1666,8 +1666,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
16661666
unsigned HasSkippedBody : 1;
16671667

16681668
/// Indicates if the function declaration will have a body, once we're done
1669-
/// parsing it. (We don't set it to false when we're done parsing, in the
1670-
/// hopes this is simpler.)
1669+
/// parsing it.
16711670
unsigned WillHaveBody : 1;
16721671

16731672
/// \brief End part of this FunctionDecl's source range.

lib/AST/DeclCXX.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -1837,9 +1837,10 @@ bool CXXMethodDecl::hasInlineBody() const {
18371837
const FunctionDecl *CheckFn = getTemplateInstantiationPattern();
18381838
if (!CheckFn)
18391839
CheckFn = this;
1840-
1840+
18411841
const FunctionDecl *fn;
1842-
return CheckFn->hasBody(fn) && !fn->isOutOfLine();
1842+
return CheckFn->isDefined(fn) && !fn->isOutOfLine() &&
1843+
(fn->doesThisDeclarationHaveABody() || fn->willHaveBody());
18431844
}
18441845

18451846
bool CXXMethodDecl::isLambdaStaticInvoker() const {

lib/Parse/ParseCXXInlineMethods.cpp

+5-18
Original file line numberDiff line numberDiff line change
@@ -166,20 +166,11 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
166166
}
167167

168168
if (FnD) {
169-
// If this is a friend function, mark that it's late-parsed so that
170-
// it's still known to be a definition even before we attach the
171-
// parsed body. Sema needs to treat friend function definitions
172-
// differently during template instantiation, and it's possible for
173-
// the containing class to be instantiated before all its member
174-
// function definitions are parsed.
175-
//
176-
// If you remove this, you can remove the code that clears the flag
177-
// after parsing the member.
178-
if (D.getDeclSpec().isFriendSpecified()) {
179-
FunctionDecl *FD = FnD->getAsFunction();
180-
Actions.CheckForFunctionRedefinition(FD);
181-
FD->setLateTemplateParsed(true);
182-
}
169+
FunctionDecl *FD = FnD->getAsFunction();
170+
// Track that this function will eventually have a body; Sema needs
171+
// to know this.
172+
Actions.CheckForFunctionRedefinition(FD);
173+
FD->setWillHaveBody(true);
183174
} else {
184175
// If semantic analysis could not build a function declaration,
185176
// just throw away the late-parsed declaration.
@@ -559,10 +550,6 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
559550

560551
ParseFunctionStatementBody(LM.D, FnScope);
561552

562-
// Clear the late-template-parsed bit if we set it before.
563-
if (LM.D)
564-
LM.D->getAsFunction()->setLateTemplateParsed(false);
565-
566553
while (Tok.isNot(tok::eof))
567554
ConsumeAnyToken();
568555

lib/Sema/SemaDecl.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -12090,8 +12090,9 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
1209012090
FD->setInvalidDecl();
1209112091
}
1209212092

12093-
// See if this is a redefinition.
12094-
if (!FD->isLateTemplateParsed()) {
12093+
// See if this is a redefinition. If 'will have body' is already set, then
12094+
// these checks were already performed when it was set.
12095+
if (!FD->willHaveBody() && !FD->isLateTemplateParsed()) {
1209512096
CheckForFunctionRedefinition(FD, nullptr, SkipBody);
1209612097

1209712098
// If we're skipping the body, we're done. Don't enter the scope.

lib/Sema/SemaTemplateInstantiateDecl.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -3771,6 +3771,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
37713771
if (PatternDef) {
37723772
Pattern = PatternDef->getBody(PatternDef);
37733773
PatternDecl = PatternDef;
3774+
if (PatternDef->willHaveBody())
3775+
PatternDef = nullptr;
37743776
}
37753777

37763778
// FIXME: We need to track the instantiation stack in order to know which

test/CodeGenCXX/pr34163.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_cc1 -emit-llvm -debug-info-kind=standalone -triple x86_64-linux-gnu -o - -x c++ %s | FileCheck %s
2+
3+
void f(struct X *) {}
4+
5+
// CHECK: @_ZTV1X =
6+
struct X {
7+
void a() { delete this; }
8+
virtual ~X() {}
9+
virtual void key_function();
10+
};
11+
12+
// CHECK: define {{.*}} @_ZN1X12key_functionEv(
13+
void X::key_function() {}

test/SemaCUDA/function-overload.cu

+1-1
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ GlobalFnPtr fp_g = g;
222222
// Test overloading of destructors
223223
// Can't mix H and unattributed destructors
224224
struct d_h {
225-
~d_h() {} // expected-note {{previous declaration is here}}
225+
~d_h() {} // expected-note {{previous definition is here}}
226226
__host__ ~d_h() {} // expected-error {{destructor cannot be redeclared}}
227227
};
228228

test/SemaCUDA/no-destructor-overload.cu

+5-5
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,27 @@
77
// giant change to clang, and the use cases seem quite limited.
88

99
struct A {
10-
~A() {} // expected-note {{previous declaration is here}}
10+
~A() {} // expected-note {{previous definition is here}}
1111
__device__ ~A() {} // expected-error {{destructor cannot be redeclared}}
1212
};
1313

1414
struct B {
15-
__host__ ~B() {} // expected-note {{previous declaration is here}}
15+
__host__ ~B() {} // expected-note {{previous definition is here}}
1616
__host__ __device__ ~B() {} // expected-error {{destructor cannot be redeclared}}
1717
};
1818

1919
struct C {
20-
__host__ __device__ ~C() {} // expected-note {{previous declaration is here}}
20+
__host__ __device__ ~C() {} // expected-note {{previous definition is here}}
2121
__host__ ~C() {} // expected-error {{destructor cannot be redeclared}}
2222
};
2323

2424
struct D {
25-
__device__ ~D() {} // expected-note {{previous declaration is here}}
25+
__device__ ~D() {} // expected-note {{previous definition is here}}
2626
__host__ __device__ ~D() {} // expected-error {{destructor cannot be redeclared}}
2727
};
2828

2929
struct E {
30-
__host__ __device__ ~E() {} // expected-note {{previous declaration is here}}
30+
__host__ __device__ ~E() {} // expected-note {{previous definition is here}}
3131
__device__ ~E() {} // expected-error {{destructor cannot be redeclared}}
3232
};
3333

0 commit comments

Comments
 (0)