Skip to content

Commit 0ec1e99

Browse files
committed
Resolve exception specifications after marking the corresponding
function as referenced, not before. No functionality change intended. This is groundwork for computing the exception specification of a defaulted comparison, for which we'd like to use the implicit body where possible.
1 parent f036f1c commit 0ec1e99

File tree

3 files changed

+50
-30
lines changed

3 files changed

+50
-30
lines changed

clang/lib/Sema/SemaExpr.cpp

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1827,6 +1827,25 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
18271827
VK, FoundD, TemplateArgs, getNonOdrUseReasonInCurrentContext(D));
18281828
MarkDeclRefReferenced(E);
18291829

1830+
// C++ [except.spec]p17:
1831+
// An exception-specification is considered to be needed when:
1832+
// - in an expression, the function is the unique lookup result or
1833+
// the selected member of a set of overloaded functions.
1834+
//
1835+
// We delay doing this until after we've built the function reference and
1836+
// marked it as used so that:
1837+
// a) if the function is defaulted, we get errors from defining it before /
1838+
// instead of errors from computing its exception specification, and
1839+
// b) if the function is a defaulted comparison, we can use the body we
1840+
// build when defining it as input to the exception specification
1841+
// computation rather than computing a new body.
1842+
if (auto *FPT = Ty->getAs<FunctionProtoType>()) {
1843+
if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
1844+
if (auto *NewFPT = ResolveExceptionSpec(NameInfo.getLoc(), FPT))
1845+
E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers()));
1846+
}
1847+
}
1848+
18301849
if (getLangOpts().ObjCWeak && isa<VarDecl>(D) &&
18311850
Ty.getObjCLifetime() == Qualifiers::OCL_Weak && !isUnevaluatedContext() &&
18321851
!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getBeginLoc()))
@@ -3009,14 +3028,6 @@ ExprResult Sema::BuildDeclarationNameExpr(
30093028
QualType type = VD->getType();
30103029
if (type.isNull())
30113030
return ExprError();
3012-
if (auto *FPT = type->getAs<FunctionProtoType>()) {
3013-
// C++ [except.spec]p17:
3014-
// An exception-specification is considered to be needed when:
3015-
// - in an expression, the function is the unique lookup result or
3016-
// the selected member of a set of overloaded functions.
3017-
ResolveExceptionSpec(Loc, FPT);
3018-
type = VD->getType();
3019-
}
30203031
ExprValueKind valueKind = VK_RValue;
30213032

30223033
switch (D->getKind()) {
@@ -15480,19 +15491,6 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
1548015491
Func->getMemberSpecializationInfo()))
1548115492
checkSpecializationVisibility(Loc, Func);
1548215493

15483-
// C++14 [except.spec]p17:
15484-
// An exception-specification is considered to be needed when:
15485-
// - the function is odr-used or, if it appears in an unevaluated operand,
15486-
// would be odr-used if the expression were potentially-evaluated;
15487-
//
15488-
// Note, we do this even if MightBeOdrUse is false. That indicates that the
15489-
// function is a pure virtual function we're calling, and in that case the
15490-
// function was selected by overload resolution and we need to resolve its
15491-
// exception specification for a different reason.
15492-
const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>();
15493-
if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
15494-
ResolveExceptionSpec(Loc, FPT);
15495-
1549615494
if (getLangOpts().CUDA)
1549715495
CheckCUDACall(Loc, Func);
1549815496

@@ -15601,6 +15599,19 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
1560115599
});
1560215600
}
1560315601

15602+
// C++14 [except.spec]p17:
15603+
// An exception-specification is considered to be needed when:
15604+
// - the function is odr-used or, if it appears in an unevaluated operand,
15605+
// would be odr-used if the expression were potentially-evaluated;
15606+
//
15607+
// Note, we do this even if MightBeOdrUse is false. That indicates that the
15608+
// function is a pure virtual function we're calling, and in that case the
15609+
// function was selected by overload resolution and we need to resolve its
15610+
// exception specification for a different reason.
15611+
const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>();
15612+
if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
15613+
ResolveExceptionSpec(Loc, FPT);
15614+
1560415615
// If this is the first "real" use, act on that.
1560515616
if (OdrUse == OdrUseContext::Used && !Func->isUsed(/*CheckUsedAttr=*/false)) {
1560615617
// Keep track of used but undefined functions.

clang/lib/Sema/SemaExprMember.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,18 @@ MemberExpr *Sema::BuildMemberExpr(
919919
VK, OK, getNonOdrUseReasonInCurrentContext(Member));
920920
E->setHadMultipleCandidates(HadMultipleCandidates);
921921
MarkMemberReferenced(E);
922+
923+
// C++ [except.spec]p17:
924+
// An exception-specification is considered to be needed when:
925+
// - in an expression the function is the unique lookup result or the
926+
// selected member of a set of overloaded functions
927+
if (auto *FPT = Ty->getAs<FunctionProtoType>()) {
928+
if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
929+
if (auto *NewFPT = ResolveExceptionSpec(MemberNameInfo.getLoc(), FPT))
930+
E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers()));
931+
}
932+
}
933+
922934
return E;
923935
}
924936

clang/lib/Sema/SemaOverload.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,18 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl,
6060
// being used.
6161
if (FoundDecl != Fn && S.DiagnoseUseOfDecl(Fn, Loc))
6262
return ExprError();
63-
if (auto *FPT = Fn->getType()->getAs<FunctionProtoType>())
64-
S.ResolveExceptionSpec(Loc, FPT);
6563
DeclRefExpr *DRE = new (S.Context)
6664
DeclRefExpr(S.Context, Fn, false, Fn->getType(), VK_LValue, Loc, LocInfo);
6765
if (HadMultipleCandidates)
6866
DRE->setHadMultipleCandidates(true);
6967

7068
S.MarkDeclRefReferenced(DRE, Base);
69+
if (auto *FPT = DRE->getType()->getAs<FunctionProtoType>()) {
70+
if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
71+
S.ResolveExceptionSpec(Loc, FPT);
72+
DRE->setType(Fn->getType());
73+
}
74+
}
7175
return S.ImpCastExprToType(DRE, S.Context.getPointerType(DRE->getType()),
7276
CK_FunctionToPointerDecay);
7377
}
@@ -14436,13 +14440,6 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
1443614440
UnOp->getOperatorLoc(), false);
1443714441
}
1443814442

14439-
// C++ [except.spec]p17:
14440-
// An exception-specification is considered to be needed when:
14441-
// - in an expression the function is the unique lookup result or the
14442-
// selected member of a set of overloaded functions
14443-
if (auto *FPT = Fn->getType()->getAs<FunctionProtoType>())
14444-
ResolveExceptionSpec(E->getExprLoc(), FPT);
14445-
1444614443
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
1444714444
// FIXME: avoid copy.
1444814445
TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr;

0 commit comments

Comments
 (0)