Skip to content

Commit 738c5ea

Browse files
committed
[FOLD] fix delayed parsing of exception specification for friend functions
1 parent eece4c2 commit 738c5ea

File tree

5 files changed

+134
-26
lines changed

5 files changed

+134
-26
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4101,7 +4101,7 @@ class Sema final : public SemaBase {
41014101
/// (or member function template). The exception-specification was parsed
41024102
/// after the method itself was declared.
41034103
void actOnDelayedExceptionSpecification(
4104-
Decl *Method, ExceptionSpecificationType EST,
4104+
Decl *D, ExceptionSpecificationType EST,
41054105
SourceRange SpecificationRange, ArrayRef<ParsedType> DynamicExceptions,
41064106
ArrayRef<SourceRange> DynamicExceptionRanges, Expr *NoexceptExpr);
41074107

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19172,21 +19172,19 @@ void Sema::checkExceptionSpecification(
1917219172
}
1917319173
}
1917419174

19175-
void Sema::actOnDelayedExceptionSpecification(Decl *MethodD,
19176-
ExceptionSpecificationType EST,
19177-
SourceRange SpecificationRange,
19178-
ArrayRef<ParsedType> DynamicExceptions,
19179-
ArrayRef<SourceRange> DynamicExceptionRanges,
19180-
Expr *NoexceptExpr) {
19181-
if (!MethodD)
19175+
void Sema::actOnDelayedExceptionSpecification(
19176+
Decl *D, ExceptionSpecificationType EST, SourceRange SpecificationRange,
19177+
ArrayRef<ParsedType> DynamicExceptions,
19178+
ArrayRef<SourceRange> DynamicExceptionRanges, Expr *NoexceptExpr) {
19179+
if (!D)
1918219180
return;
1918319181

19184-
// Dig out the method we're referring to.
19185-
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(MethodD))
19186-
MethodD = FunTmpl->getTemplatedDecl();
19182+
// Dig out the function we're referring to.
19183+
if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
19184+
D = FTD->getTemplatedDecl();
1918719185

19188-
CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(MethodD);
19189-
if (!Method)
19186+
FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
19187+
if (!FD)
1919019188
return;
1919119189

1919219190
// Check the exception specification.
@@ -19197,15 +19195,17 @@ void Sema::actOnDelayedExceptionSpecification(Decl *MethodD,
1919719195
ESI);
1919819196

1919919197
// Update the exception specification on the function type.
19200-
Context.adjustExceptionSpec(Method, ESI, /*AsWritten*/true);
19198+
Context.adjustExceptionSpec(FD, ESI, /*AsWritten*/ true);
1920119199

19202-
if (Method->isStatic())
19203-
checkThisInStaticMemberFunctionExceptionSpec(Method);
19200+
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
19201+
if (MD->isStatic())
19202+
checkThisInStaticMemberFunctionExceptionSpec(MD);
1920419203

19205-
if (Method->isVirtual()) {
19206-
// Check overrides, which we previously had to delay.
19207-
for (const CXXMethodDecl *O : Method->overridden_methods())
19208-
CheckOverridingFunctionExceptionSpec(Method, O);
19204+
if (MD->isVirtual()) {
19205+
// Check overrides, which we previously had to delay.
19206+
for (const CXXMethodDecl *O : MD->overridden_methods())
19207+
CheckOverridingFunctionExceptionSpec(MD, O);
19208+
}
1920919209
}
1921019210
}
1921119211

clang/lib/Sema/SemaExceptionSpec.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -258,13 +258,14 @@ Sema::UpdateExceptionSpec(FunctionDecl *FD,
258258
}
259259

260260
static bool exceptionSpecNotKnownYet(const FunctionDecl *FD) {
261-
auto *MD = dyn_cast<CXXMethodDecl>(FD);
262-
if (!MD)
261+
ExceptionSpecificationType EST =
262+
FD->getType()->castAs<FunctionProtoType>()->getExceptionSpecType();
263+
if (EST == EST_Unparsed)
264+
return true;
265+
else if (EST != EST_Unevaluated)
263266
return false;
264-
265-
auto EST = MD->getType()->castAs<FunctionProtoType>()->getExceptionSpecType();
266-
return EST == EST_Unparsed ||
267-
(EST == EST_Unevaluated && MD->getParent()->isBeingDefined());
267+
const DeclContext *DC = FD->getLexicalDeclContext();
268+
return DC->isRecord() && cast<RecordDecl>(DC)->isBeingDefined();
268269
}
269270

270271
static bool CheckEquivalentExceptionSpecImpl(
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
3+
namespace N0 {
4+
struct A {
5+
void f0() noexcept(x);
6+
void g0() noexcept(y); // expected-error {{use of undeclared identifier 'y'}}
7+
8+
void f1() noexcept(A::x);
9+
void g1() noexcept(A::y); // expected-error {{no member named 'y' in 'N0::A'}}
10+
11+
template<typename T>
12+
void f2() noexcept(x);
13+
template<typename T>
14+
void g2() noexcept(y); // expected-error {{use of undeclared identifier 'y'}}
15+
16+
template<typename T>
17+
void f3() noexcept(A::x);
18+
template<typename T>
19+
void g3() noexcept(A::y); // expected-error {{no member named 'y' in 'N0::A'}}
20+
21+
friend void f4() noexcept(x);
22+
friend void g4() noexcept(y); // expected-error {{use of undeclared identifier 'y'}}
23+
24+
friend void f5() noexcept(A::x);
25+
friend void g5() noexcept(A::y); // expected-error {{no member named 'y' in 'N0::A'}}
26+
27+
template<typename T>
28+
friend void f6() noexcept(x);
29+
template<typename T>
30+
friend void g6() noexcept(y); // expected-error {{use of undeclared identifier 'y'}}
31+
32+
template<typename T>
33+
friend void f7() noexcept(A::x);
34+
template<typename T>
35+
friend void g7() noexcept(A::y); // expected-error {{no member named 'y' in 'N0::A'}}
36+
37+
static constexpr bool x = true;
38+
};
39+
} // namespace N0
40+
41+
namespace N1 {
42+
template<typename T>
43+
struct A {
44+
void f0() noexcept(x);
45+
void g0() noexcept(y); // expected-error {{use of undeclared identifier 'y'}}
46+
47+
void f1() noexcept(A::x);
48+
void g1() noexcept(A::y); // expected-error {{no member named 'y' in 'A<T>'}}
49+
50+
template<typename U>
51+
void f2() noexcept(x);
52+
template<typename U>
53+
void g2() noexcept(y); // expected-error {{use of undeclared identifier 'y'}}
54+
55+
template<typename U>
56+
void f3() noexcept(A::x);
57+
template<typename U>
58+
void g3() noexcept(A::y); // expected-error {{no member named 'y' in 'A<T>'}}
59+
60+
friend void f4() noexcept(x);
61+
friend void g4() noexcept(y); // expected-error {{use of undeclared identifier 'y'}}
62+
63+
friend void f5() noexcept(A::x);
64+
friend void g5() noexcept(A::y); // expected-error {{no member named 'y' in 'A<T>'}}
65+
66+
template<typename U>
67+
friend void f6() noexcept(x);
68+
template<typename U>
69+
friend void g6() noexcept(y); // expected-error {{use of undeclared identifier 'y'}}
70+
71+
template<typename U>
72+
friend void f7() noexcept(A::x);
73+
template<typename U>
74+
friend void g7() noexcept(A::y); // expected-error {{no member named 'y' in 'A<T>'}}
75+
76+
static constexpr bool x = true;
77+
};
78+
} // namespace N1
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %clang_cc1 -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
2+
3+
namespace N0 {
4+
void f() noexcept;
5+
void g() noexcept;
6+
7+
struct A {
8+
friend void f() noexcept;
9+
friend void g() noexcept(x);
10+
11+
static constexpr bool x = true;
12+
};
13+
} // namespace N0
14+
15+
namespace N1 {
16+
void f() noexcept;
17+
void g();
18+
19+
template<typename T>
20+
struct A {
21+
friend void f() noexcept;
22+
// FIXME: This error is emitted if no other errors occured (i.e. Sema::hasUncompilableErrorOccurred() is false).
23+
friend void g() noexcept(x); // expected-error {{no member 'x' in 'N1::A<int>'; it has not yet been instantiated}}
24+
// expected-note@-1 {{in instantiation of exception specification}}
25+
static constexpr bool x = false; // expected-note {{not-yet-instantiated member is declared here}}
26+
};
27+
28+
template struct A<int>; // expected-note {{in instantiation of template class}}
29+
} // namespace N1

0 commit comments

Comments
 (0)