@@ -217,8 +217,8 @@ Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,
217
217
Exceptions.push_back(E);
218
218
}
219
219
220
- void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E ) {
221
- if (!E || ComputedEST == EST_MSAny)
220
+ void Sema::ImplicitExceptionSpecification::CalledStmt(Stmt *S ) {
221
+ if (!S || ComputedEST == EST_MSAny)
222
222
return;
223
223
224
224
// FIXME:
@@ -242,7 +242,7 @@ void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) {
242
242
// implicit definition. For now, we assume that any non-nothrow expression can
243
243
// throw any exception.
244
244
245
- if (Self->canThrow(E ))
245
+ if (Self->canThrow(S ))
246
246
ComputedEST = EST_None;
247
247
}
248
248
@@ -6814,20 +6814,50 @@ static bool defaultedSpecialMemberIsConstexpr(
6814
6814
return true;
6815
6815
}
6816
6816
6817
+ namespace {
6818
+ /// RAII object to register a defaulted function as having its exception
6819
+ /// specification computed.
6820
+ struct ComputingExceptionSpec {
6821
+ Sema &S;
6822
+
6823
+ ComputingExceptionSpec(Sema &S, FunctionDecl *FD, SourceLocation Loc)
6824
+ : S(S) {
6825
+ Sema::CodeSynthesisContext Ctx;
6826
+ Ctx.Kind = Sema::CodeSynthesisContext::ExceptionSpecEvaluation;
6827
+ Ctx.PointOfInstantiation = Loc;
6828
+ Ctx.Entity = FD;
6829
+ S.pushCodeSynthesisContext(Ctx);
6830
+ }
6831
+ ~ComputingExceptionSpec() {
6832
+ S.popCodeSynthesisContext();
6833
+ }
6834
+ };
6835
+ }
6836
+
6817
6837
static Sema::ImplicitExceptionSpecification
6818
6838
ComputeDefaultedSpecialMemberExceptionSpec(
6819
6839
Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM,
6820
6840
Sema::InheritedConstructorInfo *ICI);
6821
6841
6822
6842
static Sema::ImplicitExceptionSpecification
6823
- computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) {
6824
- auto CSM = S.getSpecialMember(MD);
6825
- if (CSM != Sema::CXXInvalid)
6826
- return ComputeDefaultedSpecialMemberExceptionSpec(S, Loc, MD, CSM, nullptr);
6843
+ ComputeDefaultedComparisonExceptionSpec(Sema &S, SourceLocation Loc,
6844
+ FunctionDecl *FD,
6845
+ Sema::DefaultedComparisonKind DCK);
6827
6846
6828
- auto *CD = cast<CXXConstructorDecl>(MD);
6847
+ static Sema::ImplicitExceptionSpecification
6848
+ computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, FunctionDecl *FD) {
6849
+ auto DFK = S.getDefaultedFunctionKind(FD);
6850
+ if (DFK.isSpecialMember())
6851
+ return ComputeDefaultedSpecialMemberExceptionSpec(
6852
+ S, Loc, cast<CXXMethodDecl>(FD), DFK.asSpecialMember(), nullptr);
6853
+ if (DFK.isComparison())
6854
+ return ComputeDefaultedComparisonExceptionSpec(S, Loc, FD,
6855
+ DFK.asComparison());
6856
+
6857
+ auto *CD = cast<CXXConstructorDecl>(FD);
6829
6858
assert(CD->getInheritedConstructor() &&
6830
- "only special members have implicit exception specs");
6859
+ "only defaulted functions and inherited constructors have implicit "
6860
+ "exception specs");
6831
6861
Sema::InheritedConstructorInfo ICI(
6832
6862
S, Loc, CD->getInheritedConstructor().getShadowDecl());
6833
6863
return ComputeDefaultedSpecialMemberExceptionSpec(
@@ -6849,25 +6879,17 @@ static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S,
6849
6879
return EPI;
6850
6880
}
6851
6881
6852
- void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD ) {
6853
- const FunctionProtoType *FPT = MD ->getType()->castAs<FunctionProtoType>();
6882
+ void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, FunctionDecl *FD ) {
6883
+ const FunctionProtoType *FPT = FD ->getType()->castAs<FunctionProtoType>();
6854
6884
if (FPT->getExceptionSpecType() != EST_Unevaluated)
6855
6885
return;
6856
6886
6857
6887
// Evaluate the exception specification.
6858
- auto IES = computeImplicitExceptionSpec(*this, Loc, MD );
6888
+ auto IES = computeImplicitExceptionSpec(*this, Loc, FD );
6859
6889
auto ESI = IES.getExceptionSpec();
6860
6890
6861
6891
// Update the type of the special member to use it.
6862
- UpdateExceptionSpec(MD, ESI);
6863
-
6864
- // A user-provided destructor can be defined outside the class. When that
6865
- // happens, be sure to update the exception specification on both
6866
- // declarations.
6867
- const FunctionProtoType *CanonicalFPT =
6868
- MD->getCanonicalDecl()->getType()->castAs<FunctionProtoType>();
6869
- if (CanonicalFPT->getExceptionSpecType() == EST_Unevaluated)
6870
- UpdateExceptionSpec(MD->getCanonicalDecl(), ESI);
6892
+ UpdateExceptionSpec(FD, ESI);
6871
6893
}
6872
6894
6873
6895
void Sema::CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *FD) {
@@ -8092,12 +8114,20 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
8092
8114
// declaration, it is implicitly considered to be constexpr.
8093
8115
// FIXME: Only applying this to the first declaration seems problematic, as
8094
8116
// simple reorderings can affect the meaning of the program.
8095
- if (First) {
8096
- if (!FD->isConstexpr() && Info.Constexpr)
8097
- FD->setConstexprKind(CSK_constexpr);
8098
-
8099
- // FIXME: Set up an implicit exception specification, or if given an
8100
- // explicit one, check that it matches.
8117
+ if (First && !FD->isConstexpr() && Info.Constexpr)
8118
+ FD->setConstexprKind(CSK_constexpr);
8119
+
8120
+ // C++2a [except.spec]p3:
8121
+ // If a declaration of a function does not have a noexcept-specifier
8122
+ // [and] is defaulted on its first declaration, [...] the exception
8123
+ // specification is as specified below
8124
+ if (FD->getExceptionSpecType() == EST_None) {
8125
+ auto *FPT = FD->getType()->castAs<FunctionProtoType>();
8126
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
8127
+ EPI.ExceptionSpec.Type = EST_Unevaluated;
8128
+ EPI.ExceptionSpec.SourceDecl = FD;
8129
+ FD->setType(Context.getFunctionType(FPT->getReturnType(),
8130
+ FPT->getParamTypes(), EPI));
8101
8131
}
8102
8132
8103
8133
return false;
@@ -8126,17 +8156,11 @@ void Sema::DefineDefaultedComparison(SourceLocation UseLoc, FunctionDecl *FD,
8126
8156
8127
8157
SynthesizedFunctionScope Scope(*this, FD);
8128
8158
8129
- // The exception specification is needed because we are defining the
8130
- // function.
8131
- // FIXME: Handle this better. Computing the exception specification will
8132
- // eventually need the function body.
8133
- ResolveExceptionSpec(UseLoc, FD->getType()->castAs<FunctionProtoType>());
8134
-
8135
8159
// Add a context note for diagnostics produced after this point.
8136
8160
Scope.addContextNote(UseLoc);
8137
8161
8138
- // Build and set up the function body.
8139
8162
{
8163
+ // Build and set up the function body.
8140
8164
CXXRecordDecl *RD = cast<CXXRecordDecl>(FD->getLexicalParent());
8141
8165
SourceLocation BodyLoc =
8142
8166
FD->getEndLoc().isValid() ? FD->getEndLoc() : FD->getLocation();
@@ -8150,10 +8174,58 @@ void Sema::DefineDefaultedComparison(SourceLocation UseLoc, FunctionDecl *FD,
8150
8174
FD->markUsed(Context);
8151
8175
}
8152
8176
8177
+ // The exception specification is needed because we are defining the
8178
+ // function. Note that this will reuse the body we just built.
8179
+ ResolveExceptionSpec(UseLoc, FD->getType()->castAs<FunctionProtoType>());
8180
+
8153
8181
if (ASTMutationListener *L = getASTMutationListener())
8154
8182
L->CompletedImplicitDefinition(FD);
8155
8183
}
8156
8184
8185
+ static Sema::ImplicitExceptionSpecification
8186
+ ComputeDefaultedComparisonExceptionSpec(Sema &S, SourceLocation Loc,
8187
+ FunctionDecl *FD,
8188
+ Sema::DefaultedComparisonKind DCK) {
8189
+ ComputingExceptionSpec CES(S, FD, Loc);
8190
+ Sema::ImplicitExceptionSpecification ExceptSpec(S);
8191
+
8192
+ if (FD->isInvalidDecl())
8193
+ return ExceptSpec;
8194
+
8195
+ // The common case is that we just defined the comparison function. In that
8196
+ // case, just look at whether the body can throw.
8197
+ if (FD->hasBody()) {
8198
+ ExceptSpec.CalledStmt(FD->getBody());
8199
+ } else {
8200
+ // Otherwise, build a body so we can check it. This should ideally only
8201
+ // happen when we're not actually marking the function referenced. (This is
8202
+ // only really important for efficiency: we don't want to build and throw
8203
+ // away bodies for comparison functions more than we strictly need to.)
8204
+
8205
+ // Pretend to synthesize the function body in an unevaluated context.
8206
+ // Note that we can't actually just go ahead and define the function here:
8207
+ // we are not permitted to mark its callees as referenced.
8208
+ Sema::SynthesizedFunctionScope Scope(S, FD);
8209
+ EnterExpressionEvaluationContext Context(
8210
+ S, Sema::ExpressionEvaluationContext::Unevaluated);
8211
+
8212
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(FD->getLexicalParent());
8213
+ SourceLocation BodyLoc =
8214
+ FD->getEndLoc().isValid() ? FD->getEndLoc() : FD->getLocation();
8215
+ StmtResult Body =
8216
+ DefaultedComparisonSynthesizer(S, RD, FD, DCK, BodyLoc).build();
8217
+ if (!Body.isInvalid())
8218
+ ExceptSpec.CalledStmt(Body.get());
8219
+
8220
+ // FIXME: Can we hold onto this body and just transform it to potentially
8221
+ // evaluated when we're asked to define the function rather than rebuilding
8222
+ // it? Either that, or we should only build the bits of the body that we
8223
+ // need (the expressions, not the statements).
8224
+ }
8225
+
8226
+ return ExceptSpec;
8227
+ }
8228
+
8157
8229
void Sema::CheckDelayedMemberExceptionSpecs() {
8158
8230
decltype(DelayedOverridingExceptionSpecChecks) Overriding;
8159
8231
decltype(DelayedEquivalentExceptionSpecChecks) Equivalent;
@@ -12336,25 +12408,6 @@ void SpecialMemberExceptionSpecInfo::visitSubobjectCall(
12336
12408
ExceptSpec.CalledDecl(getSubobjectLoc(Subobj), MD);
12337
12409
}
12338
12410
12339
- namespace {
12340
- /// RAII object to register a special member as being currently declared.
12341
- struct ComputingExceptionSpec {
12342
- Sema &S;
12343
-
12344
- ComputingExceptionSpec(Sema &S, CXXMethodDecl *MD, SourceLocation Loc)
12345
- : S(S) {
12346
- Sema::CodeSynthesisContext Ctx;
12347
- Ctx.Kind = Sema::CodeSynthesisContext::ExceptionSpecEvaluation;
12348
- Ctx.PointOfInstantiation = Loc;
12349
- Ctx.Entity = MD;
12350
- S.pushCodeSynthesisContext(Ctx);
12351
- }
12352
- ~ComputingExceptionSpec() {
12353
- S.popCodeSynthesisContext();
12354
- }
12355
- };
12356
- }
12357
-
12358
12411
bool Sema::tryResolveExplicitSpecifier(ExplicitSpecifier &ExplicitSpec) {
12359
12412
llvm::APSInt Result;
12360
12413
ExprResult Converted = CheckConvertedConstantExpression(
0 commit comments