1f4a2713aSLionel Sambuc //===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // This file provides Sema routines for C++ exception specification testing.
11f4a2713aSLionel Sambuc //
12f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
13f4a2713aSLionel Sambuc
14f4a2713aSLionel Sambuc #include "clang/Sema/SemaInternal.h"
15*0a6a1f1dSLionel Sambuc #include "clang/AST/ASTMutationListener.h"
16f4a2713aSLionel Sambuc #include "clang/AST/CXXInheritance.h"
17f4a2713aSLionel Sambuc #include "clang/AST/Expr.h"
18f4a2713aSLionel Sambuc #include "clang/AST/ExprCXX.h"
19f4a2713aSLionel Sambuc #include "clang/AST/TypeLoc.h"
20f4a2713aSLionel Sambuc #include "clang/Basic/Diagnostic.h"
21f4a2713aSLionel Sambuc #include "clang/Basic/SourceManager.h"
22f4a2713aSLionel Sambuc #include "llvm/ADT/SmallPtrSet.h"
23f4a2713aSLionel Sambuc #include "llvm/ADT/SmallString.h"
24f4a2713aSLionel Sambuc
25f4a2713aSLionel Sambuc namespace clang {
26f4a2713aSLionel Sambuc
GetUnderlyingFunction(QualType T)27f4a2713aSLionel Sambuc static const FunctionProtoType *GetUnderlyingFunction(QualType T)
28f4a2713aSLionel Sambuc {
29f4a2713aSLionel Sambuc if (const PointerType *PtrTy = T->getAs<PointerType>())
30f4a2713aSLionel Sambuc T = PtrTy->getPointeeType();
31f4a2713aSLionel Sambuc else if (const ReferenceType *RefTy = T->getAs<ReferenceType>())
32f4a2713aSLionel Sambuc T = RefTy->getPointeeType();
33f4a2713aSLionel Sambuc else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>())
34f4a2713aSLionel Sambuc T = MPTy->getPointeeType();
35f4a2713aSLionel Sambuc return T->getAs<FunctionProtoType>();
36f4a2713aSLionel Sambuc }
37f4a2713aSLionel Sambuc
38*0a6a1f1dSLionel Sambuc /// HACK: libstdc++ has a bug where it shadows std::swap with a member
39*0a6a1f1dSLionel Sambuc /// swap function then tries to call std::swap unqualified from the exception
40*0a6a1f1dSLionel Sambuc /// specification of that function. This function detects whether we're in
41*0a6a1f1dSLionel Sambuc /// such a case and turns off delay-parsing of exception specifications.
isLibstdcxxEagerExceptionSpecHack(const Declarator & D)42*0a6a1f1dSLionel Sambuc bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) {
43*0a6a1f1dSLionel Sambuc auto *RD = dyn_cast<CXXRecordDecl>(CurContext);
44*0a6a1f1dSLionel Sambuc
45*0a6a1f1dSLionel Sambuc // All the problem cases are member functions named "swap" within class
46*0a6a1f1dSLionel Sambuc // templates declared directly within namespace std.
47*0a6a1f1dSLionel Sambuc if (!RD || RD->getEnclosingNamespaceContext() != getStdNamespace() ||
48*0a6a1f1dSLionel Sambuc !RD->getIdentifier() || !RD->getDescribedClassTemplate() ||
49*0a6a1f1dSLionel Sambuc !D.getIdentifier() || !D.getIdentifier()->isStr("swap"))
50*0a6a1f1dSLionel Sambuc return false;
51*0a6a1f1dSLionel Sambuc
52*0a6a1f1dSLionel Sambuc // Only apply this hack within a system header.
53*0a6a1f1dSLionel Sambuc if (!Context.getSourceManager().isInSystemHeader(D.getLocStart()))
54*0a6a1f1dSLionel Sambuc return false;
55*0a6a1f1dSLionel Sambuc
56*0a6a1f1dSLionel Sambuc return llvm::StringSwitch<bool>(RD->getIdentifier()->getName())
57*0a6a1f1dSLionel Sambuc .Case("array", true)
58*0a6a1f1dSLionel Sambuc .Case("pair", true)
59*0a6a1f1dSLionel Sambuc .Case("priority_queue", true)
60*0a6a1f1dSLionel Sambuc .Case("stack", true)
61*0a6a1f1dSLionel Sambuc .Case("queue", true)
62*0a6a1f1dSLionel Sambuc .Default(false);
63*0a6a1f1dSLionel Sambuc }
64*0a6a1f1dSLionel Sambuc
65f4a2713aSLionel Sambuc /// CheckSpecifiedExceptionType - Check if the given type is valid in an
66f4a2713aSLionel Sambuc /// exception specification. Incomplete types, or pointers to incomplete types
67f4a2713aSLionel Sambuc /// other than void are not allowed.
68f4a2713aSLionel Sambuc ///
69f4a2713aSLionel Sambuc /// \param[in,out] T The exception type. This will be decayed to a pointer type
70f4a2713aSLionel Sambuc /// when the input is an array or a function type.
CheckSpecifiedExceptionType(QualType & T,const SourceRange & Range)71f4a2713aSLionel Sambuc bool Sema::CheckSpecifiedExceptionType(QualType &T, const SourceRange &Range) {
72f4a2713aSLionel Sambuc // C++11 [except.spec]p2:
73f4a2713aSLionel Sambuc // A type cv T, "array of T", or "function returning T" denoted
74f4a2713aSLionel Sambuc // in an exception-specification is adjusted to type T, "pointer to T", or
75f4a2713aSLionel Sambuc // "pointer to function returning T", respectively.
76f4a2713aSLionel Sambuc //
77f4a2713aSLionel Sambuc // We also apply this rule in C++98.
78f4a2713aSLionel Sambuc if (T->isArrayType())
79f4a2713aSLionel Sambuc T = Context.getArrayDecayedType(T);
80f4a2713aSLionel Sambuc else if (T->isFunctionType())
81f4a2713aSLionel Sambuc T = Context.getPointerType(T);
82f4a2713aSLionel Sambuc
83f4a2713aSLionel Sambuc int Kind = 0;
84f4a2713aSLionel Sambuc QualType PointeeT = T;
85f4a2713aSLionel Sambuc if (const PointerType *PT = T->getAs<PointerType>()) {
86f4a2713aSLionel Sambuc PointeeT = PT->getPointeeType();
87f4a2713aSLionel Sambuc Kind = 1;
88f4a2713aSLionel Sambuc
89f4a2713aSLionel Sambuc // cv void* is explicitly permitted, despite being a pointer to an
90f4a2713aSLionel Sambuc // incomplete type.
91f4a2713aSLionel Sambuc if (PointeeT->isVoidType())
92f4a2713aSLionel Sambuc return false;
93f4a2713aSLionel Sambuc } else if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
94f4a2713aSLionel Sambuc PointeeT = RT->getPointeeType();
95f4a2713aSLionel Sambuc Kind = 2;
96f4a2713aSLionel Sambuc
97f4a2713aSLionel Sambuc if (RT->isRValueReferenceType()) {
98f4a2713aSLionel Sambuc // C++11 [except.spec]p2:
99f4a2713aSLionel Sambuc // A type denoted in an exception-specification shall not denote [...]
100f4a2713aSLionel Sambuc // an rvalue reference type.
101f4a2713aSLionel Sambuc Diag(Range.getBegin(), diag::err_rref_in_exception_spec)
102f4a2713aSLionel Sambuc << T << Range;
103f4a2713aSLionel Sambuc return true;
104f4a2713aSLionel Sambuc }
105f4a2713aSLionel Sambuc }
106f4a2713aSLionel Sambuc
107f4a2713aSLionel Sambuc // C++11 [except.spec]p2:
108f4a2713aSLionel Sambuc // A type denoted in an exception-specification shall not denote an
109f4a2713aSLionel Sambuc // incomplete type other than a class currently being defined [...].
110f4a2713aSLionel Sambuc // A type denoted in an exception-specification shall not denote a
111f4a2713aSLionel Sambuc // pointer or reference to an incomplete type, other than (cv) void* or a
112f4a2713aSLionel Sambuc // pointer or reference to a class currently being defined.
113f4a2713aSLionel Sambuc if (!(PointeeT->isRecordType() &&
114f4a2713aSLionel Sambuc PointeeT->getAs<RecordType>()->isBeingDefined()) &&
115f4a2713aSLionel Sambuc RequireCompleteType(Range.getBegin(), PointeeT,
116f4a2713aSLionel Sambuc diag::err_incomplete_in_exception_spec, Kind, Range))
117f4a2713aSLionel Sambuc return true;
118f4a2713aSLionel Sambuc
119f4a2713aSLionel Sambuc return false;
120f4a2713aSLionel Sambuc }
121f4a2713aSLionel Sambuc
122f4a2713aSLionel Sambuc /// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
123f4a2713aSLionel Sambuc /// to member to a function with an exception specification. This means that
124f4a2713aSLionel Sambuc /// it is invalid to add another level of indirection.
CheckDistantExceptionSpec(QualType T)125f4a2713aSLionel Sambuc bool Sema::CheckDistantExceptionSpec(QualType T) {
126f4a2713aSLionel Sambuc if (const PointerType *PT = T->getAs<PointerType>())
127f4a2713aSLionel Sambuc T = PT->getPointeeType();
128f4a2713aSLionel Sambuc else if (const MemberPointerType *PT = T->getAs<MemberPointerType>())
129f4a2713aSLionel Sambuc T = PT->getPointeeType();
130f4a2713aSLionel Sambuc else
131f4a2713aSLionel Sambuc return false;
132f4a2713aSLionel Sambuc
133f4a2713aSLionel Sambuc const FunctionProtoType *FnT = T->getAs<FunctionProtoType>();
134f4a2713aSLionel Sambuc if (!FnT)
135f4a2713aSLionel Sambuc return false;
136f4a2713aSLionel Sambuc
137f4a2713aSLionel Sambuc return FnT->hasExceptionSpec();
138f4a2713aSLionel Sambuc }
139f4a2713aSLionel Sambuc
140f4a2713aSLionel Sambuc const FunctionProtoType *
ResolveExceptionSpec(SourceLocation Loc,const FunctionProtoType * FPT)141f4a2713aSLionel Sambuc Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
142*0a6a1f1dSLionel Sambuc if (FPT->getExceptionSpecType() == EST_Unparsed) {
143*0a6a1f1dSLionel Sambuc Diag(Loc, diag::err_exception_spec_not_parsed);
144*0a6a1f1dSLionel Sambuc return nullptr;
145*0a6a1f1dSLionel Sambuc }
146*0a6a1f1dSLionel Sambuc
147f4a2713aSLionel Sambuc if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
148f4a2713aSLionel Sambuc return FPT;
149f4a2713aSLionel Sambuc
150f4a2713aSLionel Sambuc FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl();
151f4a2713aSLionel Sambuc const FunctionProtoType *SourceFPT =
152f4a2713aSLionel Sambuc SourceDecl->getType()->castAs<FunctionProtoType>();
153f4a2713aSLionel Sambuc
154f4a2713aSLionel Sambuc // If the exception specification has already been resolved, just return it.
155f4a2713aSLionel Sambuc if (!isUnresolvedExceptionSpec(SourceFPT->getExceptionSpecType()))
156f4a2713aSLionel Sambuc return SourceFPT;
157f4a2713aSLionel Sambuc
158f4a2713aSLionel Sambuc // Compute or instantiate the exception specification now.
159f4a2713aSLionel Sambuc if (SourceFPT->getExceptionSpecType() == EST_Unevaluated)
160f4a2713aSLionel Sambuc EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl));
161f4a2713aSLionel Sambuc else
162f4a2713aSLionel Sambuc InstantiateExceptionSpec(Loc, SourceDecl);
163f4a2713aSLionel Sambuc
164f4a2713aSLionel Sambuc return SourceDecl->getType()->castAs<FunctionProtoType>();
165f4a2713aSLionel Sambuc }
166f4a2713aSLionel Sambuc
167*0a6a1f1dSLionel Sambuc void
UpdateExceptionSpec(FunctionDecl * FD,const FunctionProtoType::ExceptionSpecInfo & ESI)168*0a6a1f1dSLionel Sambuc Sema::UpdateExceptionSpec(FunctionDecl *FD,
169*0a6a1f1dSLionel Sambuc const FunctionProtoType::ExceptionSpecInfo &ESI) {
170*0a6a1f1dSLionel Sambuc for (auto *Redecl : FD->redecls())
171*0a6a1f1dSLionel Sambuc Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
172*0a6a1f1dSLionel Sambuc
173*0a6a1f1dSLionel Sambuc // If we've fully resolved the exception specification, notify listeners.
174*0a6a1f1dSLionel Sambuc if (!isUnresolvedExceptionSpec(ESI.Type))
175*0a6a1f1dSLionel Sambuc if (auto *Listener = getASTMutationListener())
176*0a6a1f1dSLionel Sambuc Listener->ResolvedExceptionSpec(FD);
177*0a6a1f1dSLionel Sambuc }
178*0a6a1f1dSLionel Sambuc
179f4a2713aSLionel Sambuc /// Determine whether a function has an implicitly-generated exception
180f4a2713aSLionel Sambuc /// specification.
hasImplicitExceptionSpec(FunctionDecl * Decl)181f4a2713aSLionel Sambuc static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
182f4a2713aSLionel Sambuc if (!isa<CXXDestructorDecl>(Decl) &&
183f4a2713aSLionel Sambuc Decl->getDeclName().getCXXOverloadedOperator() != OO_Delete &&
184f4a2713aSLionel Sambuc Decl->getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
185f4a2713aSLionel Sambuc return false;
186f4a2713aSLionel Sambuc
187*0a6a1f1dSLionel Sambuc // For a function that the user didn't declare:
188*0a6a1f1dSLionel Sambuc // - if this is a destructor, its exception specification is implicit.
189*0a6a1f1dSLionel Sambuc // - if this is 'operator delete' or 'operator delete[]', the exception
190*0a6a1f1dSLionel Sambuc // specification is as-if an explicit exception specification was given
191*0a6a1f1dSLionel Sambuc // (per [basic.stc.dynamic]p2).
192f4a2713aSLionel Sambuc if (!Decl->getTypeSourceInfo())
193*0a6a1f1dSLionel Sambuc return isa<CXXDestructorDecl>(Decl);
194f4a2713aSLionel Sambuc
195f4a2713aSLionel Sambuc const FunctionProtoType *Ty =
196f4a2713aSLionel Sambuc Decl->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>();
197f4a2713aSLionel Sambuc return !Ty->hasExceptionSpec();
198f4a2713aSLionel Sambuc }
199f4a2713aSLionel Sambuc
CheckEquivalentExceptionSpec(FunctionDecl * Old,FunctionDecl * New)200f4a2713aSLionel Sambuc bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
201f4a2713aSLionel Sambuc OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator();
202f4a2713aSLionel Sambuc bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;
203f4a2713aSLionel Sambuc bool MissingExceptionSpecification = false;
204f4a2713aSLionel Sambuc bool MissingEmptyExceptionSpecification = false;
205*0a6a1f1dSLionel Sambuc
206f4a2713aSLionel Sambuc unsigned DiagID = diag::err_mismatched_exception_spec;
207*0a6a1f1dSLionel Sambuc bool ReturnValueOnError = true;
208*0a6a1f1dSLionel Sambuc if (getLangOpts().MicrosoftExt) {
209*0a6a1f1dSLionel Sambuc DiagID = diag::ext_mismatched_exception_spec;
210*0a6a1f1dSLionel Sambuc ReturnValueOnError = false;
211*0a6a1f1dSLionel Sambuc }
212f4a2713aSLionel Sambuc
213f4a2713aSLionel Sambuc // Check the types as written: they must match before any exception
214f4a2713aSLionel Sambuc // specification adjustment is applied.
215f4a2713aSLionel Sambuc if (!CheckEquivalentExceptionSpec(
216f4a2713aSLionel Sambuc PDiag(DiagID), PDiag(diag::note_previous_declaration),
217f4a2713aSLionel Sambuc Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
218f4a2713aSLionel Sambuc New->getType()->getAs<FunctionProtoType>(), New->getLocation(),
219f4a2713aSLionel Sambuc &MissingExceptionSpecification, &MissingEmptyExceptionSpecification,
220f4a2713aSLionel Sambuc /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) {
221f4a2713aSLionel Sambuc // C++11 [except.spec]p4 [DR1492]:
222f4a2713aSLionel Sambuc // If a declaration of a function has an implicit
223f4a2713aSLionel Sambuc // exception-specification, other declarations of the function shall
224f4a2713aSLionel Sambuc // not specify an exception-specification.
225f4a2713aSLionel Sambuc if (getLangOpts().CPlusPlus11 &&
226f4a2713aSLionel Sambuc hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) {
227f4a2713aSLionel Sambuc Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch)
228f4a2713aSLionel Sambuc << hasImplicitExceptionSpec(Old);
229f4a2713aSLionel Sambuc if (!Old->getLocation().isInvalid())
230f4a2713aSLionel Sambuc Diag(Old->getLocation(), diag::note_previous_declaration);
231f4a2713aSLionel Sambuc }
232f4a2713aSLionel Sambuc return false;
233f4a2713aSLionel Sambuc }
234f4a2713aSLionel Sambuc
235f4a2713aSLionel Sambuc // The failure was something other than an missing exception
236*0a6a1f1dSLionel Sambuc // specification; return an error, except in MS mode where this is a warning.
237f4a2713aSLionel Sambuc if (!MissingExceptionSpecification)
238*0a6a1f1dSLionel Sambuc return ReturnValueOnError;
239f4a2713aSLionel Sambuc
240f4a2713aSLionel Sambuc const FunctionProtoType *NewProto =
241f4a2713aSLionel Sambuc New->getType()->castAs<FunctionProtoType>();
242f4a2713aSLionel Sambuc
243f4a2713aSLionel Sambuc // The new function declaration is only missing an empty exception
244f4a2713aSLionel Sambuc // specification "throw()". If the throw() specification came from a
245f4a2713aSLionel Sambuc // function in a system header that has C linkage, just add an empty
246f4a2713aSLionel Sambuc // exception specification to the "new" declaration. This is an
247f4a2713aSLionel Sambuc // egregious workaround for glibc, which adds throw() specifications
248f4a2713aSLionel Sambuc // to many libc functions as an optimization. Unfortunately, that
249f4a2713aSLionel Sambuc // optimization isn't permitted by the C++ standard, so we're forced
250f4a2713aSLionel Sambuc // to work around it here.
251f4a2713aSLionel Sambuc if (MissingEmptyExceptionSpecification && NewProto &&
252f4a2713aSLionel Sambuc (Old->getLocation().isInvalid() ||
253f4a2713aSLionel Sambuc Context.getSourceManager().isInSystemHeader(Old->getLocation())) &&
254f4a2713aSLionel Sambuc Old->isExternC()) {
255*0a6a1f1dSLionel Sambuc New->setType(Context.getFunctionType(
256*0a6a1f1dSLionel Sambuc NewProto->getReturnType(), NewProto->getParamTypes(),
257*0a6a1f1dSLionel Sambuc NewProto->getExtProtoInfo().withExceptionSpec(EST_DynamicNone)));
258f4a2713aSLionel Sambuc return false;
259f4a2713aSLionel Sambuc }
260f4a2713aSLionel Sambuc
261f4a2713aSLionel Sambuc const FunctionProtoType *OldProto =
262f4a2713aSLionel Sambuc Old->getType()->castAs<FunctionProtoType>();
263f4a2713aSLionel Sambuc
264*0a6a1f1dSLionel Sambuc FunctionProtoType::ExceptionSpecInfo ESI = OldProto->getExceptionSpecType();
265*0a6a1f1dSLionel Sambuc if (ESI.Type == EST_Dynamic) {
266*0a6a1f1dSLionel Sambuc ESI.Exceptions = OldProto->exceptions();
267*0a6a1f1dSLionel Sambuc } else if (ESI.Type == EST_ComputedNoexcept) {
268f4a2713aSLionel Sambuc // FIXME: We can't just take the expression from the old prototype. It
269f4a2713aSLionel Sambuc // likely contains references to the old prototype's parameters.
270f4a2713aSLionel Sambuc }
271f4a2713aSLionel Sambuc
272f4a2713aSLionel Sambuc // Update the type of the function with the appropriate exception
273f4a2713aSLionel Sambuc // specification.
274*0a6a1f1dSLionel Sambuc New->setType(Context.getFunctionType(
275*0a6a1f1dSLionel Sambuc NewProto->getReturnType(), NewProto->getParamTypes(),
276*0a6a1f1dSLionel Sambuc NewProto->getExtProtoInfo().withExceptionSpec(ESI)));
277f4a2713aSLionel Sambuc
278f4a2713aSLionel Sambuc // Warn about the lack of exception specification.
279f4a2713aSLionel Sambuc SmallString<128> ExceptionSpecString;
280f4a2713aSLionel Sambuc llvm::raw_svector_ostream OS(ExceptionSpecString);
281f4a2713aSLionel Sambuc switch (OldProto->getExceptionSpecType()) {
282f4a2713aSLionel Sambuc case EST_DynamicNone:
283f4a2713aSLionel Sambuc OS << "throw()";
284f4a2713aSLionel Sambuc break;
285f4a2713aSLionel Sambuc
286f4a2713aSLionel Sambuc case EST_Dynamic: {
287f4a2713aSLionel Sambuc OS << "throw(";
288f4a2713aSLionel Sambuc bool OnFirstException = true;
289*0a6a1f1dSLionel Sambuc for (const auto &E : OldProto->exceptions()) {
290f4a2713aSLionel Sambuc if (OnFirstException)
291f4a2713aSLionel Sambuc OnFirstException = false;
292f4a2713aSLionel Sambuc else
293f4a2713aSLionel Sambuc OS << ", ";
294f4a2713aSLionel Sambuc
295*0a6a1f1dSLionel Sambuc OS << E.getAsString(getPrintingPolicy());
296f4a2713aSLionel Sambuc }
297f4a2713aSLionel Sambuc OS << ")";
298f4a2713aSLionel Sambuc break;
299f4a2713aSLionel Sambuc }
300f4a2713aSLionel Sambuc
301f4a2713aSLionel Sambuc case EST_BasicNoexcept:
302f4a2713aSLionel Sambuc OS << "noexcept";
303f4a2713aSLionel Sambuc break;
304f4a2713aSLionel Sambuc
305f4a2713aSLionel Sambuc case EST_ComputedNoexcept:
306f4a2713aSLionel Sambuc OS << "noexcept(";
307*0a6a1f1dSLionel Sambuc assert(OldProto->getNoexceptExpr() != nullptr && "Expected non-null Expr");
308*0a6a1f1dSLionel Sambuc OldProto->getNoexceptExpr()->printPretty(OS, nullptr, getPrintingPolicy());
309f4a2713aSLionel Sambuc OS << ")";
310f4a2713aSLionel Sambuc break;
311f4a2713aSLionel Sambuc
312f4a2713aSLionel Sambuc default:
313f4a2713aSLionel Sambuc llvm_unreachable("This spec type is compatible with none.");
314f4a2713aSLionel Sambuc }
315f4a2713aSLionel Sambuc OS.flush();
316f4a2713aSLionel Sambuc
317f4a2713aSLionel Sambuc SourceLocation FixItLoc;
318f4a2713aSLionel Sambuc if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) {
319f4a2713aSLionel Sambuc TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();
320f4a2713aSLionel Sambuc if (FunctionTypeLoc FTLoc = TL.getAs<FunctionTypeLoc>())
321*0a6a1f1dSLionel Sambuc FixItLoc = getLocForEndOfToken(FTLoc.getLocalRangeEnd());
322f4a2713aSLionel Sambuc }
323f4a2713aSLionel Sambuc
324f4a2713aSLionel Sambuc if (FixItLoc.isInvalid())
325f4a2713aSLionel Sambuc Diag(New->getLocation(), diag::warn_missing_exception_specification)
326f4a2713aSLionel Sambuc << New << OS.str();
327f4a2713aSLionel Sambuc else {
328f4a2713aSLionel Sambuc // FIXME: This will get more complicated with C++0x
329f4a2713aSLionel Sambuc // late-specified return types.
330f4a2713aSLionel Sambuc Diag(New->getLocation(), diag::warn_missing_exception_specification)
331f4a2713aSLionel Sambuc << New << OS.str()
332f4a2713aSLionel Sambuc << FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str());
333f4a2713aSLionel Sambuc }
334f4a2713aSLionel Sambuc
335f4a2713aSLionel Sambuc if (!Old->getLocation().isInvalid())
336f4a2713aSLionel Sambuc Diag(Old->getLocation(), diag::note_previous_declaration);
337f4a2713aSLionel Sambuc
338f4a2713aSLionel Sambuc return false;
339f4a2713aSLionel Sambuc }
340f4a2713aSLionel Sambuc
341f4a2713aSLionel Sambuc /// CheckEquivalentExceptionSpec - Check if the two types have equivalent
342f4a2713aSLionel Sambuc /// exception specifications. Exception specifications are equivalent if
343f4a2713aSLionel Sambuc /// they allow exactly the same set of exception types. It does not matter how
344f4a2713aSLionel Sambuc /// that is achieved. See C++ [except.spec]p2.
CheckEquivalentExceptionSpec(const FunctionProtoType * Old,SourceLocation OldLoc,const FunctionProtoType * New,SourceLocation NewLoc)345f4a2713aSLionel Sambuc bool Sema::CheckEquivalentExceptionSpec(
346f4a2713aSLionel Sambuc const FunctionProtoType *Old, SourceLocation OldLoc,
347f4a2713aSLionel Sambuc const FunctionProtoType *New, SourceLocation NewLoc) {
348f4a2713aSLionel Sambuc unsigned DiagID = diag::err_mismatched_exception_spec;
349f4a2713aSLionel Sambuc if (getLangOpts().MicrosoftExt)
350*0a6a1f1dSLionel Sambuc DiagID = diag::ext_mismatched_exception_spec;
351*0a6a1f1dSLionel Sambuc bool Result = CheckEquivalentExceptionSpec(PDiag(DiagID),
352*0a6a1f1dSLionel Sambuc PDiag(diag::note_previous_declaration), Old, OldLoc, New, NewLoc);
353*0a6a1f1dSLionel Sambuc
354*0a6a1f1dSLionel Sambuc // In Microsoft mode, mismatching exception specifications just cause a warning.
355*0a6a1f1dSLionel Sambuc if (getLangOpts().MicrosoftExt)
356*0a6a1f1dSLionel Sambuc return false;
357*0a6a1f1dSLionel Sambuc return Result;
358f4a2713aSLionel Sambuc }
359f4a2713aSLionel Sambuc
360f4a2713aSLionel Sambuc /// CheckEquivalentExceptionSpec - Check if the two types have compatible
361f4a2713aSLionel Sambuc /// exception specifications. See C++ [except.spec]p3.
362f4a2713aSLionel Sambuc ///
363f4a2713aSLionel Sambuc /// \return \c false if the exception specifications match, \c true if there is
364f4a2713aSLionel Sambuc /// a problem. If \c true is returned, either a diagnostic has already been
365f4a2713aSLionel Sambuc /// produced or \c *MissingExceptionSpecification is set to \c true.
CheckEquivalentExceptionSpec(const PartialDiagnostic & DiagID,const PartialDiagnostic & NoteID,const FunctionProtoType * Old,SourceLocation OldLoc,const FunctionProtoType * New,SourceLocation NewLoc,bool * MissingExceptionSpecification,bool * MissingEmptyExceptionSpecification,bool AllowNoexceptAllMatchWithNoSpec,bool IsOperatorNew)366f4a2713aSLionel Sambuc bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
367f4a2713aSLionel Sambuc const PartialDiagnostic & NoteID,
368f4a2713aSLionel Sambuc const FunctionProtoType *Old,
369f4a2713aSLionel Sambuc SourceLocation OldLoc,
370f4a2713aSLionel Sambuc const FunctionProtoType *New,
371f4a2713aSLionel Sambuc SourceLocation NewLoc,
372f4a2713aSLionel Sambuc bool *MissingExceptionSpecification,
373f4a2713aSLionel Sambuc bool*MissingEmptyExceptionSpecification,
374f4a2713aSLionel Sambuc bool AllowNoexceptAllMatchWithNoSpec,
375f4a2713aSLionel Sambuc bool IsOperatorNew) {
376f4a2713aSLionel Sambuc // Just completely ignore this under -fno-exceptions.
377f4a2713aSLionel Sambuc if (!getLangOpts().CXXExceptions)
378f4a2713aSLionel Sambuc return false;
379f4a2713aSLionel Sambuc
380f4a2713aSLionel Sambuc if (MissingExceptionSpecification)
381f4a2713aSLionel Sambuc *MissingExceptionSpecification = false;
382f4a2713aSLionel Sambuc
383f4a2713aSLionel Sambuc if (MissingEmptyExceptionSpecification)
384f4a2713aSLionel Sambuc *MissingEmptyExceptionSpecification = false;
385f4a2713aSLionel Sambuc
386f4a2713aSLionel Sambuc Old = ResolveExceptionSpec(NewLoc, Old);
387f4a2713aSLionel Sambuc if (!Old)
388f4a2713aSLionel Sambuc return false;
389f4a2713aSLionel Sambuc New = ResolveExceptionSpec(NewLoc, New);
390f4a2713aSLionel Sambuc if (!New)
391f4a2713aSLionel Sambuc return false;
392f4a2713aSLionel Sambuc
393f4a2713aSLionel Sambuc // C++0x [except.spec]p3: Two exception-specifications are compatible if:
394f4a2713aSLionel Sambuc // - both are non-throwing, regardless of their form,
395f4a2713aSLionel Sambuc // - both have the form noexcept(constant-expression) and the constant-
396f4a2713aSLionel Sambuc // expressions are equivalent,
397f4a2713aSLionel Sambuc // - both are dynamic-exception-specifications that have the same set of
398f4a2713aSLionel Sambuc // adjusted types.
399f4a2713aSLionel Sambuc //
400f4a2713aSLionel Sambuc // C++0x [except.spec]p12: An exception-specifcation is non-throwing if it is
401f4a2713aSLionel Sambuc // of the form throw(), noexcept, or noexcept(constant-expression) where the
402f4a2713aSLionel Sambuc // constant-expression yields true.
403f4a2713aSLionel Sambuc //
404f4a2713aSLionel Sambuc // C++0x [except.spec]p4: If any declaration of a function has an exception-
405f4a2713aSLionel Sambuc // specifier that is not a noexcept-specification allowing all exceptions,
406f4a2713aSLionel Sambuc // all declarations [...] of that function shall have a compatible
407f4a2713aSLionel Sambuc // exception-specification.
408f4a2713aSLionel Sambuc //
409f4a2713aSLionel Sambuc // That last point basically means that noexcept(false) matches no spec.
410f4a2713aSLionel Sambuc // It's considered when AllowNoexceptAllMatchWithNoSpec is true.
411f4a2713aSLionel Sambuc
412f4a2713aSLionel Sambuc ExceptionSpecificationType OldEST = Old->getExceptionSpecType();
413f4a2713aSLionel Sambuc ExceptionSpecificationType NewEST = New->getExceptionSpecType();
414f4a2713aSLionel Sambuc
415f4a2713aSLionel Sambuc assert(!isUnresolvedExceptionSpec(OldEST) &&
416f4a2713aSLionel Sambuc !isUnresolvedExceptionSpec(NewEST) &&
417f4a2713aSLionel Sambuc "Shouldn't see unknown exception specifications here");
418f4a2713aSLionel Sambuc
419f4a2713aSLionel Sambuc // Shortcut the case where both have no spec.
420f4a2713aSLionel Sambuc if (OldEST == EST_None && NewEST == EST_None)
421f4a2713aSLionel Sambuc return false;
422f4a2713aSLionel Sambuc
423f4a2713aSLionel Sambuc FunctionProtoType::NoexceptResult OldNR = Old->getNoexceptSpec(Context);
424f4a2713aSLionel Sambuc FunctionProtoType::NoexceptResult NewNR = New->getNoexceptSpec(Context);
425f4a2713aSLionel Sambuc if (OldNR == FunctionProtoType::NR_BadNoexcept ||
426f4a2713aSLionel Sambuc NewNR == FunctionProtoType::NR_BadNoexcept)
427f4a2713aSLionel Sambuc return false;
428f4a2713aSLionel Sambuc
429f4a2713aSLionel Sambuc // Dependent noexcept specifiers are compatible with each other, but nothing
430f4a2713aSLionel Sambuc // else.
431f4a2713aSLionel Sambuc // One noexcept is compatible with another if the argument is the same
432f4a2713aSLionel Sambuc if (OldNR == NewNR &&
433f4a2713aSLionel Sambuc OldNR != FunctionProtoType::NR_NoNoexcept &&
434f4a2713aSLionel Sambuc NewNR != FunctionProtoType::NR_NoNoexcept)
435f4a2713aSLionel Sambuc return false;
436f4a2713aSLionel Sambuc if (OldNR != NewNR &&
437f4a2713aSLionel Sambuc OldNR != FunctionProtoType::NR_NoNoexcept &&
438f4a2713aSLionel Sambuc NewNR != FunctionProtoType::NR_NoNoexcept) {
439f4a2713aSLionel Sambuc Diag(NewLoc, DiagID);
440f4a2713aSLionel Sambuc if (NoteID.getDiagID() != 0)
441f4a2713aSLionel Sambuc Diag(OldLoc, NoteID);
442f4a2713aSLionel Sambuc return true;
443f4a2713aSLionel Sambuc }
444f4a2713aSLionel Sambuc
445f4a2713aSLionel Sambuc // The MS extension throw(...) is compatible with itself.
446f4a2713aSLionel Sambuc if (OldEST == EST_MSAny && NewEST == EST_MSAny)
447f4a2713aSLionel Sambuc return false;
448f4a2713aSLionel Sambuc
449f4a2713aSLionel Sambuc // It's also compatible with no spec.
450f4a2713aSLionel Sambuc if ((OldEST == EST_None && NewEST == EST_MSAny) ||
451f4a2713aSLionel Sambuc (OldEST == EST_MSAny && NewEST == EST_None))
452f4a2713aSLionel Sambuc return false;
453f4a2713aSLionel Sambuc
454f4a2713aSLionel Sambuc // It's also compatible with noexcept(false).
455f4a2713aSLionel Sambuc if (OldEST == EST_MSAny && NewNR == FunctionProtoType::NR_Throw)
456f4a2713aSLionel Sambuc return false;
457f4a2713aSLionel Sambuc if (NewEST == EST_MSAny && OldNR == FunctionProtoType::NR_Throw)
458f4a2713aSLionel Sambuc return false;
459f4a2713aSLionel Sambuc
460f4a2713aSLionel Sambuc // As described above, noexcept(false) matches no spec only for functions.
461f4a2713aSLionel Sambuc if (AllowNoexceptAllMatchWithNoSpec) {
462f4a2713aSLionel Sambuc if (OldEST == EST_None && NewNR == FunctionProtoType::NR_Throw)
463f4a2713aSLionel Sambuc return false;
464f4a2713aSLionel Sambuc if (NewEST == EST_None && OldNR == FunctionProtoType::NR_Throw)
465f4a2713aSLionel Sambuc return false;
466f4a2713aSLionel Sambuc }
467f4a2713aSLionel Sambuc
468f4a2713aSLionel Sambuc // Any non-throwing specifications are compatible.
469f4a2713aSLionel Sambuc bool OldNonThrowing = OldNR == FunctionProtoType::NR_Nothrow ||
470f4a2713aSLionel Sambuc OldEST == EST_DynamicNone;
471f4a2713aSLionel Sambuc bool NewNonThrowing = NewNR == FunctionProtoType::NR_Nothrow ||
472f4a2713aSLionel Sambuc NewEST == EST_DynamicNone;
473f4a2713aSLionel Sambuc if (OldNonThrowing && NewNonThrowing)
474f4a2713aSLionel Sambuc return false;
475f4a2713aSLionel Sambuc
476f4a2713aSLionel Sambuc // As a special compatibility feature, under C++0x we accept no spec and
477f4a2713aSLionel Sambuc // throw(std::bad_alloc) as equivalent for operator new and operator new[].
478f4a2713aSLionel Sambuc // This is because the implicit declaration changed, but old code would break.
479f4a2713aSLionel Sambuc if (getLangOpts().CPlusPlus11 && IsOperatorNew) {
480*0a6a1f1dSLionel Sambuc const FunctionProtoType *WithExceptions = nullptr;
481f4a2713aSLionel Sambuc if (OldEST == EST_None && NewEST == EST_Dynamic)
482f4a2713aSLionel Sambuc WithExceptions = New;
483f4a2713aSLionel Sambuc else if (OldEST == EST_Dynamic && NewEST == EST_None)
484f4a2713aSLionel Sambuc WithExceptions = Old;
485f4a2713aSLionel Sambuc if (WithExceptions && WithExceptions->getNumExceptions() == 1) {
486f4a2713aSLionel Sambuc // One has no spec, the other throw(something). If that something is
487f4a2713aSLionel Sambuc // std::bad_alloc, all conditions are met.
488f4a2713aSLionel Sambuc QualType Exception = *WithExceptions->exception_begin();
489f4a2713aSLionel Sambuc if (CXXRecordDecl *ExRecord = Exception->getAsCXXRecordDecl()) {
490f4a2713aSLionel Sambuc IdentifierInfo* Name = ExRecord->getIdentifier();
491f4a2713aSLionel Sambuc if (Name && Name->getName() == "bad_alloc") {
492f4a2713aSLionel Sambuc // It's called bad_alloc, but is it in std?
493*0a6a1f1dSLionel Sambuc if (ExRecord->isInStdNamespace()) {
494f4a2713aSLionel Sambuc return false;
495f4a2713aSLionel Sambuc }
496f4a2713aSLionel Sambuc }
497f4a2713aSLionel Sambuc }
498f4a2713aSLionel Sambuc }
499f4a2713aSLionel Sambuc }
500f4a2713aSLionel Sambuc
501f4a2713aSLionel Sambuc // At this point, the only remaining valid case is two matching dynamic
502f4a2713aSLionel Sambuc // specifications. We return here unless both specifications are dynamic.
503f4a2713aSLionel Sambuc if (OldEST != EST_Dynamic || NewEST != EST_Dynamic) {
504f4a2713aSLionel Sambuc if (MissingExceptionSpecification && Old->hasExceptionSpec() &&
505f4a2713aSLionel Sambuc !New->hasExceptionSpec()) {
506f4a2713aSLionel Sambuc // The old type has an exception specification of some sort, but
507f4a2713aSLionel Sambuc // the new type does not.
508f4a2713aSLionel Sambuc *MissingExceptionSpecification = true;
509f4a2713aSLionel Sambuc
510f4a2713aSLionel Sambuc if (MissingEmptyExceptionSpecification && OldNonThrowing) {
511f4a2713aSLionel Sambuc // The old type has a throw() or noexcept(true) exception specification
512f4a2713aSLionel Sambuc // and the new type has no exception specification, and the caller asked
513f4a2713aSLionel Sambuc // to handle this itself.
514f4a2713aSLionel Sambuc *MissingEmptyExceptionSpecification = true;
515f4a2713aSLionel Sambuc }
516f4a2713aSLionel Sambuc
517f4a2713aSLionel Sambuc return true;
518f4a2713aSLionel Sambuc }
519f4a2713aSLionel Sambuc
520f4a2713aSLionel Sambuc Diag(NewLoc, DiagID);
521f4a2713aSLionel Sambuc if (NoteID.getDiagID() != 0)
522f4a2713aSLionel Sambuc Diag(OldLoc, NoteID);
523f4a2713aSLionel Sambuc return true;
524f4a2713aSLionel Sambuc }
525f4a2713aSLionel Sambuc
526f4a2713aSLionel Sambuc assert(OldEST == EST_Dynamic && NewEST == EST_Dynamic &&
527f4a2713aSLionel Sambuc "Exception compatibility logic error: non-dynamic spec slipped through.");
528f4a2713aSLionel Sambuc
529f4a2713aSLionel Sambuc bool Success = true;
530f4a2713aSLionel Sambuc // Both have a dynamic exception spec. Collect the first set, then compare
531f4a2713aSLionel Sambuc // to the second.
532f4a2713aSLionel Sambuc llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes;
533*0a6a1f1dSLionel Sambuc for (const auto &I : Old->exceptions())
534*0a6a1f1dSLionel Sambuc OldTypes.insert(Context.getCanonicalType(I).getUnqualifiedType());
535f4a2713aSLionel Sambuc
536*0a6a1f1dSLionel Sambuc for (const auto &I : New->exceptions()) {
537*0a6a1f1dSLionel Sambuc CanQualType TypePtr = Context.getCanonicalType(I).getUnqualifiedType();
538f4a2713aSLionel Sambuc if(OldTypes.count(TypePtr))
539f4a2713aSLionel Sambuc NewTypes.insert(TypePtr);
540f4a2713aSLionel Sambuc else
541f4a2713aSLionel Sambuc Success = false;
542f4a2713aSLionel Sambuc }
543f4a2713aSLionel Sambuc
544f4a2713aSLionel Sambuc Success = Success && OldTypes.size() == NewTypes.size();
545f4a2713aSLionel Sambuc
546f4a2713aSLionel Sambuc if (Success) {
547f4a2713aSLionel Sambuc return false;
548f4a2713aSLionel Sambuc }
549f4a2713aSLionel Sambuc Diag(NewLoc, DiagID);
550f4a2713aSLionel Sambuc if (NoteID.getDiagID() != 0)
551f4a2713aSLionel Sambuc Diag(OldLoc, NoteID);
552f4a2713aSLionel Sambuc return true;
553f4a2713aSLionel Sambuc }
554f4a2713aSLionel Sambuc
555f4a2713aSLionel Sambuc /// CheckExceptionSpecSubset - Check whether the second function type's
556f4a2713aSLionel Sambuc /// exception specification is a subset (or equivalent) of the first function
557f4a2713aSLionel Sambuc /// type. This is used by override and pointer assignment checks.
CheckExceptionSpecSubset(const PartialDiagnostic & DiagID,const PartialDiagnostic & NoteID,const FunctionProtoType * Superset,SourceLocation SuperLoc,const FunctionProtoType * Subset,SourceLocation SubLoc)558f4a2713aSLionel Sambuc bool Sema::CheckExceptionSpecSubset(
559f4a2713aSLionel Sambuc const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
560f4a2713aSLionel Sambuc const FunctionProtoType *Superset, SourceLocation SuperLoc,
561f4a2713aSLionel Sambuc const FunctionProtoType *Subset, SourceLocation SubLoc) {
562f4a2713aSLionel Sambuc
563f4a2713aSLionel Sambuc // Just auto-succeed under -fno-exceptions.
564f4a2713aSLionel Sambuc if (!getLangOpts().CXXExceptions)
565f4a2713aSLionel Sambuc return false;
566f4a2713aSLionel Sambuc
567f4a2713aSLionel Sambuc // FIXME: As usual, we could be more specific in our error messages, but
568f4a2713aSLionel Sambuc // that better waits until we've got types with source locations.
569f4a2713aSLionel Sambuc
570f4a2713aSLionel Sambuc if (!SubLoc.isValid())
571f4a2713aSLionel Sambuc SubLoc = SuperLoc;
572f4a2713aSLionel Sambuc
573f4a2713aSLionel Sambuc // Resolve the exception specifications, if needed.
574f4a2713aSLionel Sambuc Superset = ResolveExceptionSpec(SuperLoc, Superset);
575f4a2713aSLionel Sambuc if (!Superset)
576f4a2713aSLionel Sambuc return false;
577f4a2713aSLionel Sambuc Subset = ResolveExceptionSpec(SubLoc, Subset);
578f4a2713aSLionel Sambuc if (!Subset)
579f4a2713aSLionel Sambuc return false;
580f4a2713aSLionel Sambuc
581f4a2713aSLionel Sambuc ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType();
582f4a2713aSLionel Sambuc
583f4a2713aSLionel Sambuc // If superset contains everything, we're done.
584f4a2713aSLionel Sambuc if (SuperEST == EST_None || SuperEST == EST_MSAny)
585f4a2713aSLionel Sambuc return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
586f4a2713aSLionel Sambuc
587f4a2713aSLionel Sambuc // If there are dependent noexcept specs, assume everything is fine. Unlike
588f4a2713aSLionel Sambuc // with the equivalency check, this is safe in this case, because we don't
589f4a2713aSLionel Sambuc // want to merge declarations. Checks after instantiation will catch any
590f4a2713aSLionel Sambuc // omissions we make here.
591f4a2713aSLionel Sambuc // We also shortcut checking if a noexcept expression was bad.
592f4a2713aSLionel Sambuc
593f4a2713aSLionel Sambuc FunctionProtoType::NoexceptResult SuperNR =Superset->getNoexceptSpec(Context);
594f4a2713aSLionel Sambuc if (SuperNR == FunctionProtoType::NR_BadNoexcept ||
595f4a2713aSLionel Sambuc SuperNR == FunctionProtoType::NR_Dependent)
596f4a2713aSLionel Sambuc return false;
597f4a2713aSLionel Sambuc
598f4a2713aSLionel Sambuc // Another case of the superset containing everything.
599f4a2713aSLionel Sambuc if (SuperNR == FunctionProtoType::NR_Throw)
600f4a2713aSLionel Sambuc return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
601f4a2713aSLionel Sambuc
602f4a2713aSLionel Sambuc ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
603f4a2713aSLionel Sambuc
604f4a2713aSLionel Sambuc assert(!isUnresolvedExceptionSpec(SuperEST) &&
605f4a2713aSLionel Sambuc !isUnresolvedExceptionSpec(SubEST) &&
606f4a2713aSLionel Sambuc "Shouldn't see unknown exception specifications here");
607f4a2713aSLionel Sambuc
608f4a2713aSLionel Sambuc // It does not. If the subset contains everything, we've failed.
609f4a2713aSLionel Sambuc if (SubEST == EST_None || SubEST == EST_MSAny) {
610f4a2713aSLionel Sambuc Diag(SubLoc, DiagID);
611f4a2713aSLionel Sambuc if (NoteID.getDiagID() != 0)
612f4a2713aSLionel Sambuc Diag(SuperLoc, NoteID);
613f4a2713aSLionel Sambuc return true;
614f4a2713aSLionel Sambuc }
615f4a2713aSLionel Sambuc
616f4a2713aSLionel Sambuc FunctionProtoType::NoexceptResult SubNR = Subset->getNoexceptSpec(Context);
617f4a2713aSLionel Sambuc if (SubNR == FunctionProtoType::NR_BadNoexcept ||
618f4a2713aSLionel Sambuc SubNR == FunctionProtoType::NR_Dependent)
619f4a2713aSLionel Sambuc return false;
620f4a2713aSLionel Sambuc
621f4a2713aSLionel Sambuc // Another case of the subset containing everything.
622f4a2713aSLionel Sambuc if (SubNR == FunctionProtoType::NR_Throw) {
623f4a2713aSLionel Sambuc Diag(SubLoc, DiagID);
624f4a2713aSLionel Sambuc if (NoteID.getDiagID() != 0)
625f4a2713aSLionel Sambuc Diag(SuperLoc, NoteID);
626f4a2713aSLionel Sambuc return true;
627f4a2713aSLionel Sambuc }
628f4a2713aSLionel Sambuc
629f4a2713aSLionel Sambuc // If the subset contains nothing, we're done.
630f4a2713aSLionel Sambuc if (SubEST == EST_DynamicNone || SubNR == FunctionProtoType::NR_Nothrow)
631f4a2713aSLionel Sambuc return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
632f4a2713aSLionel Sambuc
633f4a2713aSLionel Sambuc // Otherwise, if the superset contains nothing, we've failed.
634f4a2713aSLionel Sambuc if (SuperEST == EST_DynamicNone || SuperNR == FunctionProtoType::NR_Nothrow) {
635f4a2713aSLionel Sambuc Diag(SubLoc, DiagID);
636f4a2713aSLionel Sambuc if (NoteID.getDiagID() != 0)
637f4a2713aSLionel Sambuc Diag(SuperLoc, NoteID);
638f4a2713aSLionel Sambuc return true;
639f4a2713aSLionel Sambuc }
640f4a2713aSLionel Sambuc
641f4a2713aSLionel Sambuc assert(SuperEST == EST_Dynamic && SubEST == EST_Dynamic &&
642f4a2713aSLionel Sambuc "Exception spec subset: non-dynamic case slipped through.");
643f4a2713aSLionel Sambuc
644f4a2713aSLionel Sambuc // Neither contains everything or nothing. Do a proper comparison.
645*0a6a1f1dSLionel Sambuc for (const auto &SubI : Subset->exceptions()) {
646f4a2713aSLionel Sambuc // Take one type from the subset.
647*0a6a1f1dSLionel Sambuc QualType CanonicalSubT = Context.getCanonicalType(SubI);
648f4a2713aSLionel Sambuc // Unwrap pointers and references so that we can do checks within a class
649f4a2713aSLionel Sambuc // hierarchy. Don't unwrap member pointers; they don't have hierarchy
650f4a2713aSLionel Sambuc // conversions on the pointee.
651f4a2713aSLionel Sambuc bool SubIsPointer = false;
652f4a2713aSLionel Sambuc if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>())
653f4a2713aSLionel Sambuc CanonicalSubT = RefTy->getPointeeType();
654f4a2713aSLionel Sambuc if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) {
655f4a2713aSLionel Sambuc CanonicalSubT = PtrTy->getPointeeType();
656f4a2713aSLionel Sambuc SubIsPointer = true;
657f4a2713aSLionel Sambuc }
658f4a2713aSLionel Sambuc bool SubIsClass = CanonicalSubT->isRecordType();
659f4a2713aSLionel Sambuc CanonicalSubT = CanonicalSubT.getLocalUnqualifiedType();
660f4a2713aSLionel Sambuc
661f4a2713aSLionel Sambuc CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
662f4a2713aSLionel Sambuc /*DetectVirtual=*/false);
663f4a2713aSLionel Sambuc
664f4a2713aSLionel Sambuc bool Contained = false;
665f4a2713aSLionel Sambuc // Make sure it's in the superset.
666*0a6a1f1dSLionel Sambuc for (const auto &SuperI : Superset->exceptions()) {
667*0a6a1f1dSLionel Sambuc QualType CanonicalSuperT = Context.getCanonicalType(SuperI);
668f4a2713aSLionel Sambuc // SubT must be SuperT or derived from it, or pointer or reference to
669f4a2713aSLionel Sambuc // such types.
670f4a2713aSLionel Sambuc if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>())
671f4a2713aSLionel Sambuc CanonicalSuperT = RefTy->getPointeeType();
672f4a2713aSLionel Sambuc if (SubIsPointer) {
673f4a2713aSLionel Sambuc if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>())
674f4a2713aSLionel Sambuc CanonicalSuperT = PtrTy->getPointeeType();
675f4a2713aSLionel Sambuc else {
676f4a2713aSLionel Sambuc continue;
677f4a2713aSLionel Sambuc }
678f4a2713aSLionel Sambuc }
679f4a2713aSLionel Sambuc CanonicalSuperT = CanonicalSuperT.getLocalUnqualifiedType();
680f4a2713aSLionel Sambuc // If the types are the same, move on to the next type in the subset.
681f4a2713aSLionel Sambuc if (CanonicalSubT == CanonicalSuperT) {
682f4a2713aSLionel Sambuc Contained = true;
683f4a2713aSLionel Sambuc break;
684f4a2713aSLionel Sambuc }
685f4a2713aSLionel Sambuc
686f4a2713aSLionel Sambuc // Otherwise we need to check the inheritance.
687f4a2713aSLionel Sambuc if (!SubIsClass || !CanonicalSuperT->isRecordType())
688f4a2713aSLionel Sambuc continue;
689f4a2713aSLionel Sambuc
690f4a2713aSLionel Sambuc Paths.clear();
691f4a2713aSLionel Sambuc if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths))
692f4a2713aSLionel Sambuc continue;
693f4a2713aSLionel Sambuc
694f4a2713aSLionel Sambuc if (Paths.isAmbiguous(Context.getCanonicalType(CanonicalSuperT)))
695f4a2713aSLionel Sambuc continue;
696f4a2713aSLionel Sambuc
697f4a2713aSLionel Sambuc // Do this check from a context without privileges.
698f4a2713aSLionel Sambuc switch (CheckBaseClassAccess(SourceLocation(),
699f4a2713aSLionel Sambuc CanonicalSuperT, CanonicalSubT,
700f4a2713aSLionel Sambuc Paths.front(),
701f4a2713aSLionel Sambuc /*Diagnostic*/ 0,
702f4a2713aSLionel Sambuc /*ForceCheck*/ true,
703f4a2713aSLionel Sambuc /*ForceUnprivileged*/ true)) {
704f4a2713aSLionel Sambuc case AR_accessible: break;
705f4a2713aSLionel Sambuc case AR_inaccessible: continue;
706f4a2713aSLionel Sambuc case AR_dependent:
707f4a2713aSLionel Sambuc llvm_unreachable("access check dependent for unprivileged context");
708f4a2713aSLionel Sambuc case AR_delayed:
709f4a2713aSLionel Sambuc llvm_unreachable("access check delayed in non-declaration");
710f4a2713aSLionel Sambuc }
711f4a2713aSLionel Sambuc
712f4a2713aSLionel Sambuc Contained = true;
713f4a2713aSLionel Sambuc break;
714f4a2713aSLionel Sambuc }
715f4a2713aSLionel Sambuc if (!Contained) {
716f4a2713aSLionel Sambuc Diag(SubLoc, DiagID);
717f4a2713aSLionel Sambuc if (NoteID.getDiagID() != 0)
718f4a2713aSLionel Sambuc Diag(SuperLoc, NoteID);
719f4a2713aSLionel Sambuc return true;
720f4a2713aSLionel Sambuc }
721f4a2713aSLionel Sambuc }
722f4a2713aSLionel Sambuc // We've run half the gauntlet.
723f4a2713aSLionel Sambuc return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
724f4a2713aSLionel Sambuc }
725f4a2713aSLionel Sambuc
CheckSpecForTypesEquivalent(Sema & S,const PartialDiagnostic & DiagID,const PartialDiagnostic & NoteID,QualType Target,SourceLocation TargetLoc,QualType Source,SourceLocation SourceLoc)726f4a2713aSLionel Sambuc static bool CheckSpecForTypesEquivalent(Sema &S,
727f4a2713aSLionel Sambuc const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
728f4a2713aSLionel Sambuc QualType Target, SourceLocation TargetLoc,
729f4a2713aSLionel Sambuc QualType Source, SourceLocation SourceLoc)
730f4a2713aSLionel Sambuc {
731f4a2713aSLionel Sambuc const FunctionProtoType *TFunc = GetUnderlyingFunction(Target);
732f4a2713aSLionel Sambuc if (!TFunc)
733f4a2713aSLionel Sambuc return false;
734f4a2713aSLionel Sambuc const FunctionProtoType *SFunc = GetUnderlyingFunction(Source);
735f4a2713aSLionel Sambuc if (!SFunc)
736f4a2713aSLionel Sambuc return false;
737f4a2713aSLionel Sambuc
738f4a2713aSLionel Sambuc return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc,
739f4a2713aSLionel Sambuc SFunc, SourceLoc);
740f4a2713aSLionel Sambuc }
741f4a2713aSLionel Sambuc
742f4a2713aSLionel Sambuc /// CheckParamExceptionSpec - Check if the parameter and return types of the
743f4a2713aSLionel Sambuc /// two functions have equivalent exception specs. This is part of the
744f4a2713aSLionel Sambuc /// assignment and override compatibility check. We do not check the parameters
745f4a2713aSLionel Sambuc /// of parameter function pointers recursively, as no sane programmer would
746f4a2713aSLionel Sambuc /// even be able to write such a function type.
CheckParamExceptionSpec(const PartialDiagnostic & NoteID,const FunctionProtoType * Target,SourceLocation TargetLoc,const FunctionProtoType * Source,SourceLocation SourceLoc)747f4a2713aSLionel Sambuc bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &NoteID,
748*0a6a1f1dSLionel Sambuc const FunctionProtoType *Target,
749*0a6a1f1dSLionel Sambuc SourceLocation TargetLoc,
750*0a6a1f1dSLionel Sambuc const FunctionProtoType *Source,
751*0a6a1f1dSLionel Sambuc SourceLocation SourceLoc) {
752*0a6a1f1dSLionel Sambuc if (CheckSpecForTypesEquivalent(
753*0a6a1f1dSLionel Sambuc *this, PDiag(diag::err_deep_exception_specs_differ) << 0, PDiag(),
754*0a6a1f1dSLionel Sambuc Target->getReturnType(), TargetLoc, Source->getReturnType(),
755*0a6a1f1dSLionel Sambuc SourceLoc))
756f4a2713aSLionel Sambuc return true;
757f4a2713aSLionel Sambuc
758f4a2713aSLionel Sambuc // We shouldn't even be testing this unless the arguments are otherwise
759f4a2713aSLionel Sambuc // compatible.
760*0a6a1f1dSLionel Sambuc assert(Target->getNumParams() == Source->getNumParams() &&
761f4a2713aSLionel Sambuc "Functions have different argument counts.");
762*0a6a1f1dSLionel Sambuc for (unsigned i = 0, E = Target->getNumParams(); i != E; ++i) {
763*0a6a1f1dSLionel Sambuc if (CheckSpecForTypesEquivalent(
764*0a6a1f1dSLionel Sambuc *this, PDiag(diag::err_deep_exception_specs_differ) << 1, PDiag(),
765*0a6a1f1dSLionel Sambuc Target->getParamType(i), TargetLoc, Source->getParamType(i),
766*0a6a1f1dSLionel Sambuc SourceLoc))
767f4a2713aSLionel Sambuc return true;
768f4a2713aSLionel Sambuc }
769f4a2713aSLionel Sambuc return false;
770f4a2713aSLionel Sambuc }
771f4a2713aSLionel Sambuc
CheckExceptionSpecCompatibility(Expr * From,QualType ToType)772*0a6a1f1dSLionel Sambuc bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) {
773f4a2713aSLionel Sambuc // First we check for applicability.
774f4a2713aSLionel Sambuc // Target type must be a function, function pointer or function reference.
775f4a2713aSLionel Sambuc const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType);
776*0a6a1f1dSLionel Sambuc if (!ToFunc || ToFunc->hasDependentExceptionSpec())
777f4a2713aSLionel Sambuc return false;
778f4a2713aSLionel Sambuc
779f4a2713aSLionel Sambuc // SourceType must be a function or function pointer.
780f4a2713aSLionel Sambuc const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType());
781*0a6a1f1dSLionel Sambuc if (!FromFunc || FromFunc->hasDependentExceptionSpec())
782f4a2713aSLionel Sambuc return false;
783f4a2713aSLionel Sambuc
784f4a2713aSLionel Sambuc // Now we've got the correct types on both sides, check their compatibility.
785f4a2713aSLionel Sambuc // This means that the source of the conversion can only throw a subset of
786f4a2713aSLionel Sambuc // the exceptions of the target, and any exception specs on arguments or
787f4a2713aSLionel Sambuc // return types must be equivalent.
788*0a6a1f1dSLionel Sambuc //
789*0a6a1f1dSLionel Sambuc // FIXME: If there is a nested dependent exception specification, we should
790*0a6a1f1dSLionel Sambuc // not be checking it here. This is fine:
791*0a6a1f1dSLionel Sambuc // template<typename T> void f() {
792*0a6a1f1dSLionel Sambuc // void (*p)(void (*) throw(T));
793*0a6a1f1dSLionel Sambuc // void (*q)(void (*) throw(int)) = p;
794*0a6a1f1dSLionel Sambuc // }
795*0a6a1f1dSLionel Sambuc // ... because it might be instantiated with T=int.
796f4a2713aSLionel Sambuc return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs),
797f4a2713aSLionel Sambuc PDiag(), ToFunc,
798f4a2713aSLionel Sambuc From->getSourceRange().getBegin(),
799f4a2713aSLionel Sambuc FromFunc, SourceLocation());
800f4a2713aSLionel Sambuc }
801f4a2713aSLionel Sambuc
CheckOverridingFunctionExceptionSpec(const CXXMethodDecl * New,const CXXMethodDecl * Old)802f4a2713aSLionel Sambuc bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
803f4a2713aSLionel Sambuc const CXXMethodDecl *Old) {
804*0a6a1f1dSLionel Sambuc // If the new exception specification hasn't been parsed yet, skip the check.
805*0a6a1f1dSLionel Sambuc // We'll get called again once it's been parsed.
806*0a6a1f1dSLionel Sambuc if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==
807*0a6a1f1dSLionel Sambuc EST_Unparsed)
808*0a6a1f1dSLionel Sambuc return false;
809f4a2713aSLionel Sambuc if (getLangOpts().CPlusPlus11 && isa<CXXDestructorDecl>(New)) {
810f4a2713aSLionel Sambuc // Don't check uninstantiated template destructors at all. We can only
811f4a2713aSLionel Sambuc // synthesize correct specs after the template is instantiated.
812f4a2713aSLionel Sambuc if (New->getParent()->isDependentType())
813f4a2713aSLionel Sambuc return false;
814f4a2713aSLionel Sambuc if (New->getParent()->isBeingDefined()) {
815f4a2713aSLionel Sambuc // The destructor might be updated once the definition is finished. So
816f4a2713aSLionel Sambuc // remember it and check later.
817*0a6a1f1dSLionel Sambuc DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old));
818f4a2713aSLionel Sambuc return false;
819f4a2713aSLionel Sambuc }
820f4a2713aSLionel Sambuc }
821*0a6a1f1dSLionel Sambuc // If the old exception specification hasn't been parsed yet, remember that
822*0a6a1f1dSLionel Sambuc // we need to perform this check when we get to the end of the outermost
823*0a6a1f1dSLionel Sambuc // lexically-surrounding class.
824*0a6a1f1dSLionel Sambuc if (Old->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==
825*0a6a1f1dSLionel Sambuc EST_Unparsed) {
826*0a6a1f1dSLionel Sambuc DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old));
827*0a6a1f1dSLionel Sambuc return false;
828*0a6a1f1dSLionel Sambuc }
829f4a2713aSLionel Sambuc unsigned DiagID = diag::err_override_exception_spec;
830f4a2713aSLionel Sambuc if (getLangOpts().MicrosoftExt)
831*0a6a1f1dSLionel Sambuc DiagID = diag::ext_override_exception_spec;
832f4a2713aSLionel Sambuc return CheckExceptionSpecSubset(PDiag(DiagID),
833f4a2713aSLionel Sambuc PDiag(diag::note_overridden_virtual_function),
834f4a2713aSLionel Sambuc Old->getType()->getAs<FunctionProtoType>(),
835f4a2713aSLionel Sambuc Old->getLocation(),
836f4a2713aSLionel Sambuc New->getType()->getAs<FunctionProtoType>(),
837f4a2713aSLionel Sambuc New->getLocation());
838f4a2713aSLionel Sambuc }
839f4a2713aSLionel Sambuc
canSubExprsThrow(Sema & S,const Expr * CE)840f4a2713aSLionel Sambuc static CanThrowResult canSubExprsThrow(Sema &S, const Expr *CE) {
841f4a2713aSLionel Sambuc Expr *E = const_cast<Expr*>(CE);
842f4a2713aSLionel Sambuc CanThrowResult R = CT_Cannot;
843f4a2713aSLionel Sambuc for (Expr::child_range I = E->children(); I && R != CT_Can; ++I)
844f4a2713aSLionel Sambuc R = mergeCanThrow(R, S.canThrow(cast<Expr>(*I)));
845f4a2713aSLionel Sambuc return R;
846f4a2713aSLionel Sambuc }
847f4a2713aSLionel Sambuc
canCalleeThrow(Sema & S,const Expr * E,const Decl * D)848f4a2713aSLionel Sambuc static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) {
849f4a2713aSLionel Sambuc assert(D && "Expected decl");
850f4a2713aSLionel Sambuc
851f4a2713aSLionel Sambuc // See if we can get a function type from the decl somehow.
852f4a2713aSLionel Sambuc const ValueDecl *VD = dyn_cast<ValueDecl>(D);
853f4a2713aSLionel Sambuc if (!VD) // If we have no clue what we're calling, assume the worst.
854f4a2713aSLionel Sambuc return CT_Can;
855f4a2713aSLionel Sambuc
856f4a2713aSLionel Sambuc // As an extension, we assume that __attribute__((nothrow)) functions don't
857f4a2713aSLionel Sambuc // throw.
858f4a2713aSLionel Sambuc if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
859f4a2713aSLionel Sambuc return CT_Cannot;
860f4a2713aSLionel Sambuc
861f4a2713aSLionel Sambuc QualType T = VD->getType();
862f4a2713aSLionel Sambuc const FunctionProtoType *FT;
863f4a2713aSLionel Sambuc if ((FT = T->getAs<FunctionProtoType>())) {
864f4a2713aSLionel Sambuc } else if (const PointerType *PT = T->getAs<PointerType>())
865f4a2713aSLionel Sambuc FT = PT->getPointeeType()->getAs<FunctionProtoType>();
866f4a2713aSLionel Sambuc else if (const ReferenceType *RT = T->getAs<ReferenceType>())
867f4a2713aSLionel Sambuc FT = RT->getPointeeType()->getAs<FunctionProtoType>();
868f4a2713aSLionel Sambuc else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())
869f4a2713aSLionel Sambuc FT = MT->getPointeeType()->getAs<FunctionProtoType>();
870f4a2713aSLionel Sambuc else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())
871f4a2713aSLionel Sambuc FT = BT->getPointeeType()->getAs<FunctionProtoType>();
872f4a2713aSLionel Sambuc
873f4a2713aSLionel Sambuc if (!FT)
874f4a2713aSLionel Sambuc return CT_Can;
875f4a2713aSLionel Sambuc
876f4a2713aSLionel Sambuc FT = S.ResolveExceptionSpec(E->getLocStart(), FT);
877f4a2713aSLionel Sambuc if (!FT)
878f4a2713aSLionel Sambuc return CT_Can;
879f4a2713aSLionel Sambuc
880f4a2713aSLionel Sambuc return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can;
881f4a2713aSLionel Sambuc }
882f4a2713aSLionel Sambuc
canDynamicCastThrow(const CXXDynamicCastExpr * DC)883f4a2713aSLionel Sambuc static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) {
884f4a2713aSLionel Sambuc if (DC->isTypeDependent())
885f4a2713aSLionel Sambuc return CT_Dependent;
886f4a2713aSLionel Sambuc
887f4a2713aSLionel Sambuc if (!DC->getTypeAsWritten()->isReferenceType())
888f4a2713aSLionel Sambuc return CT_Cannot;
889f4a2713aSLionel Sambuc
890f4a2713aSLionel Sambuc if (DC->getSubExpr()->isTypeDependent())
891f4a2713aSLionel Sambuc return CT_Dependent;
892f4a2713aSLionel Sambuc
893f4a2713aSLionel Sambuc return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot;
894f4a2713aSLionel Sambuc }
895f4a2713aSLionel Sambuc
canTypeidThrow(Sema & S,const CXXTypeidExpr * DC)896f4a2713aSLionel Sambuc static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) {
897f4a2713aSLionel Sambuc if (DC->isTypeOperand())
898f4a2713aSLionel Sambuc return CT_Cannot;
899f4a2713aSLionel Sambuc
900f4a2713aSLionel Sambuc Expr *Op = DC->getExprOperand();
901f4a2713aSLionel Sambuc if (Op->isTypeDependent())
902f4a2713aSLionel Sambuc return CT_Dependent;
903f4a2713aSLionel Sambuc
904f4a2713aSLionel Sambuc const RecordType *RT = Op->getType()->getAs<RecordType>();
905f4a2713aSLionel Sambuc if (!RT)
906f4a2713aSLionel Sambuc return CT_Cannot;
907f4a2713aSLionel Sambuc
908f4a2713aSLionel Sambuc if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())
909f4a2713aSLionel Sambuc return CT_Cannot;
910f4a2713aSLionel Sambuc
911f4a2713aSLionel Sambuc if (Op->Classify(S.Context).isPRValue())
912f4a2713aSLionel Sambuc return CT_Cannot;
913f4a2713aSLionel Sambuc
914f4a2713aSLionel Sambuc return CT_Can;
915f4a2713aSLionel Sambuc }
916f4a2713aSLionel Sambuc
canThrow(const Expr * E)917f4a2713aSLionel Sambuc CanThrowResult Sema::canThrow(const Expr *E) {
918f4a2713aSLionel Sambuc // C++ [expr.unary.noexcept]p3:
919f4a2713aSLionel Sambuc // [Can throw] if in a potentially-evaluated context the expression would
920f4a2713aSLionel Sambuc // contain:
921f4a2713aSLionel Sambuc switch (E->getStmtClass()) {
922f4a2713aSLionel Sambuc case Expr::CXXThrowExprClass:
923f4a2713aSLionel Sambuc // - a potentially evaluated throw-expression
924f4a2713aSLionel Sambuc return CT_Can;
925f4a2713aSLionel Sambuc
926f4a2713aSLionel Sambuc case Expr::CXXDynamicCastExprClass: {
927f4a2713aSLionel Sambuc // - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),
928f4a2713aSLionel Sambuc // where T is a reference type, that requires a run-time check
929f4a2713aSLionel Sambuc CanThrowResult CT = canDynamicCastThrow(cast<CXXDynamicCastExpr>(E));
930f4a2713aSLionel Sambuc if (CT == CT_Can)
931f4a2713aSLionel Sambuc return CT;
932f4a2713aSLionel Sambuc return mergeCanThrow(CT, canSubExprsThrow(*this, E));
933f4a2713aSLionel Sambuc }
934f4a2713aSLionel Sambuc
935f4a2713aSLionel Sambuc case Expr::CXXTypeidExprClass:
936f4a2713aSLionel Sambuc // - a potentially evaluated typeid expression applied to a glvalue
937f4a2713aSLionel Sambuc // expression whose type is a polymorphic class type
938f4a2713aSLionel Sambuc return canTypeidThrow(*this, cast<CXXTypeidExpr>(E));
939f4a2713aSLionel Sambuc
940f4a2713aSLionel Sambuc // - a potentially evaluated call to a function, member function, function
941f4a2713aSLionel Sambuc // pointer, or member function pointer that does not have a non-throwing
942f4a2713aSLionel Sambuc // exception-specification
943f4a2713aSLionel Sambuc case Expr::CallExprClass:
944f4a2713aSLionel Sambuc case Expr::CXXMemberCallExprClass:
945f4a2713aSLionel Sambuc case Expr::CXXOperatorCallExprClass:
946f4a2713aSLionel Sambuc case Expr::UserDefinedLiteralClass: {
947f4a2713aSLionel Sambuc const CallExpr *CE = cast<CallExpr>(E);
948f4a2713aSLionel Sambuc CanThrowResult CT;
949f4a2713aSLionel Sambuc if (E->isTypeDependent())
950f4a2713aSLionel Sambuc CT = CT_Dependent;
951f4a2713aSLionel Sambuc else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
952f4a2713aSLionel Sambuc CT = CT_Cannot;
953f4a2713aSLionel Sambuc else if (CE->getCalleeDecl())
954f4a2713aSLionel Sambuc CT = canCalleeThrow(*this, E, CE->getCalleeDecl());
955f4a2713aSLionel Sambuc else
956f4a2713aSLionel Sambuc CT = CT_Can;
957f4a2713aSLionel Sambuc if (CT == CT_Can)
958f4a2713aSLionel Sambuc return CT;
959f4a2713aSLionel Sambuc return mergeCanThrow(CT, canSubExprsThrow(*this, E));
960f4a2713aSLionel Sambuc }
961f4a2713aSLionel Sambuc
962f4a2713aSLionel Sambuc case Expr::CXXConstructExprClass:
963f4a2713aSLionel Sambuc case Expr::CXXTemporaryObjectExprClass: {
964f4a2713aSLionel Sambuc CanThrowResult CT = canCalleeThrow(*this, E,
965f4a2713aSLionel Sambuc cast<CXXConstructExpr>(E)->getConstructor());
966f4a2713aSLionel Sambuc if (CT == CT_Can)
967f4a2713aSLionel Sambuc return CT;
968f4a2713aSLionel Sambuc return mergeCanThrow(CT, canSubExprsThrow(*this, E));
969f4a2713aSLionel Sambuc }
970f4a2713aSLionel Sambuc
971f4a2713aSLionel Sambuc case Expr::LambdaExprClass: {
972f4a2713aSLionel Sambuc const LambdaExpr *Lambda = cast<LambdaExpr>(E);
973f4a2713aSLionel Sambuc CanThrowResult CT = CT_Cannot;
974f4a2713aSLionel Sambuc for (LambdaExpr::capture_init_iterator Cap = Lambda->capture_init_begin(),
975f4a2713aSLionel Sambuc CapEnd = Lambda->capture_init_end();
976f4a2713aSLionel Sambuc Cap != CapEnd; ++Cap)
977f4a2713aSLionel Sambuc CT = mergeCanThrow(CT, canThrow(*Cap));
978f4a2713aSLionel Sambuc return CT;
979f4a2713aSLionel Sambuc }
980f4a2713aSLionel Sambuc
981f4a2713aSLionel Sambuc case Expr::CXXNewExprClass: {
982f4a2713aSLionel Sambuc CanThrowResult CT;
983f4a2713aSLionel Sambuc if (E->isTypeDependent())
984f4a2713aSLionel Sambuc CT = CT_Dependent;
985f4a2713aSLionel Sambuc else
986f4a2713aSLionel Sambuc CT = canCalleeThrow(*this, E, cast<CXXNewExpr>(E)->getOperatorNew());
987f4a2713aSLionel Sambuc if (CT == CT_Can)
988f4a2713aSLionel Sambuc return CT;
989f4a2713aSLionel Sambuc return mergeCanThrow(CT, canSubExprsThrow(*this, E));
990f4a2713aSLionel Sambuc }
991f4a2713aSLionel Sambuc
992f4a2713aSLionel Sambuc case Expr::CXXDeleteExprClass: {
993f4a2713aSLionel Sambuc CanThrowResult CT;
994f4a2713aSLionel Sambuc QualType DTy = cast<CXXDeleteExpr>(E)->getDestroyedType();
995f4a2713aSLionel Sambuc if (DTy.isNull() || DTy->isDependentType()) {
996f4a2713aSLionel Sambuc CT = CT_Dependent;
997f4a2713aSLionel Sambuc } else {
998f4a2713aSLionel Sambuc CT = canCalleeThrow(*this, E,
999f4a2713aSLionel Sambuc cast<CXXDeleteExpr>(E)->getOperatorDelete());
1000f4a2713aSLionel Sambuc if (const RecordType *RT = DTy->getAs<RecordType>()) {
1001f4a2713aSLionel Sambuc const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
1002f4a2713aSLionel Sambuc const CXXDestructorDecl *DD = RD->getDestructor();
1003f4a2713aSLionel Sambuc if (DD)
1004f4a2713aSLionel Sambuc CT = mergeCanThrow(CT, canCalleeThrow(*this, E, DD));
1005f4a2713aSLionel Sambuc }
1006f4a2713aSLionel Sambuc if (CT == CT_Can)
1007f4a2713aSLionel Sambuc return CT;
1008f4a2713aSLionel Sambuc }
1009f4a2713aSLionel Sambuc return mergeCanThrow(CT, canSubExprsThrow(*this, E));
1010f4a2713aSLionel Sambuc }
1011f4a2713aSLionel Sambuc
1012f4a2713aSLionel Sambuc case Expr::CXXBindTemporaryExprClass: {
1013f4a2713aSLionel Sambuc // The bound temporary has to be destroyed again, which might throw.
1014f4a2713aSLionel Sambuc CanThrowResult CT = canCalleeThrow(*this, E,
1015f4a2713aSLionel Sambuc cast<CXXBindTemporaryExpr>(E)->getTemporary()->getDestructor());
1016f4a2713aSLionel Sambuc if (CT == CT_Can)
1017f4a2713aSLionel Sambuc return CT;
1018f4a2713aSLionel Sambuc return mergeCanThrow(CT, canSubExprsThrow(*this, E));
1019f4a2713aSLionel Sambuc }
1020f4a2713aSLionel Sambuc
1021f4a2713aSLionel Sambuc // ObjC message sends are like function calls, but never have exception
1022f4a2713aSLionel Sambuc // specs.
1023f4a2713aSLionel Sambuc case Expr::ObjCMessageExprClass:
1024f4a2713aSLionel Sambuc case Expr::ObjCPropertyRefExprClass:
1025f4a2713aSLionel Sambuc case Expr::ObjCSubscriptRefExprClass:
1026f4a2713aSLionel Sambuc return CT_Can;
1027f4a2713aSLionel Sambuc
1028f4a2713aSLionel Sambuc // All the ObjC literals that are implemented as calls are
1029f4a2713aSLionel Sambuc // potentially throwing unless we decide to close off that
1030f4a2713aSLionel Sambuc // possibility.
1031f4a2713aSLionel Sambuc case Expr::ObjCArrayLiteralClass:
1032f4a2713aSLionel Sambuc case Expr::ObjCDictionaryLiteralClass:
1033f4a2713aSLionel Sambuc case Expr::ObjCBoxedExprClass:
1034f4a2713aSLionel Sambuc return CT_Can;
1035f4a2713aSLionel Sambuc
1036f4a2713aSLionel Sambuc // Many other things have subexpressions, so we have to test those.
1037f4a2713aSLionel Sambuc // Some are simple:
1038f4a2713aSLionel Sambuc case Expr::ConditionalOperatorClass:
1039f4a2713aSLionel Sambuc case Expr::CompoundLiteralExprClass:
1040f4a2713aSLionel Sambuc case Expr::CXXConstCastExprClass:
1041f4a2713aSLionel Sambuc case Expr::CXXReinterpretCastExprClass:
1042f4a2713aSLionel Sambuc case Expr::CXXStdInitializerListExprClass:
1043f4a2713aSLionel Sambuc case Expr::DesignatedInitExprClass:
1044f4a2713aSLionel Sambuc case Expr::ExprWithCleanupsClass:
1045f4a2713aSLionel Sambuc case Expr::ExtVectorElementExprClass:
1046f4a2713aSLionel Sambuc case Expr::InitListExprClass:
1047f4a2713aSLionel Sambuc case Expr::MemberExprClass:
1048f4a2713aSLionel Sambuc case Expr::ObjCIsaExprClass:
1049f4a2713aSLionel Sambuc case Expr::ObjCIvarRefExprClass:
1050f4a2713aSLionel Sambuc case Expr::ParenExprClass:
1051f4a2713aSLionel Sambuc case Expr::ParenListExprClass:
1052f4a2713aSLionel Sambuc case Expr::ShuffleVectorExprClass:
1053f4a2713aSLionel Sambuc case Expr::ConvertVectorExprClass:
1054f4a2713aSLionel Sambuc case Expr::VAArgExprClass:
1055f4a2713aSLionel Sambuc return canSubExprsThrow(*this, E);
1056f4a2713aSLionel Sambuc
1057f4a2713aSLionel Sambuc // Some might be dependent for other reasons.
1058f4a2713aSLionel Sambuc case Expr::ArraySubscriptExprClass:
1059f4a2713aSLionel Sambuc case Expr::BinaryOperatorClass:
1060f4a2713aSLionel Sambuc case Expr::CompoundAssignOperatorClass:
1061f4a2713aSLionel Sambuc case Expr::CStyleCastExprClass:
1062f4a2713aSLionel Sambuc case Expr::CXXStaticCastExprClass:
1063f4a2713aSLionel Sambuc case Expr::CXXFunctionalCastExprClass:
1064f4a2713aSLionel Sambuc case Expr::ImplicitCastExprClass:
1065f4a2713aSLionel Sambuc case Expr::MaterializeTemporaryExprClass:
1066f4a2713aSLionel Sambuc case Expr::UnaryOperatorClass: {
1067f4a2713aSLionel Sambuc CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot;
1068f4a2713aSLionel Sambuc return mergeCanThrow(CT, canSubExprsThrow(*this, E));
1069f4a2713aSLionel Sambuc }
1070f4a2713aSLionel Sambuc
1071f4a2713aSLionel Sambuc // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms.
1072f4a2713aSLionel Sambuc case Expr::StmtExprClass:
1073f4a2713aSLionel Sambuc return CT_Can;
1074f4a2713aSLionel Sambuc
1075f4a2713aSLionel Sambuc case Expr::CXXDefaultArgExprClass:
1076f4a2713aSLionel Sambuc return canThrow(cast<CXXDefaultArgExpr>(E)->getExpr());
1077f4a2713aSLionel Sambuc
1078f4a2713aSLionel Sambuc case Expr::CXXDefaultInitExprClass:
1079f4a2713aSLionel Sambuc return canThrow(cast<CXXDefaultInitExpr>(E)->getExpr());
1080f4a2713aSLionel Sambuc
1081f4a2713aSLionel Sambuc case Expr::ChooseExprClass:
1082f4a2713aSLionel Sambuc if (E->isTypeDependent() || E->isValueDependent())
1083f4a2713aSLionel Sambuc return CT_Dependent;
1084f4a2713aSLionel Sambuc return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr());
1085f4a2713aSLionel Sambuc
1086f4a2713aSLionel Sambuc case Expr::GenericSelectionExprClass:
1087f4a2713aSLionel Sambuc if (cast<GenericSelectionExpr>(E)->isResultDependent())
1088f4a2713aSLionel Sambuc return CT_Dependent;
1089f4a2713aSLionel Sambuc return canThrow(cast<GenericSelectionExpr>(E)->getResultExpr());
1090f4a2713aSLionel Sambuc
1091f4a2713aSLionel Sambuc // Some expressions are always dependent.
1092f4a2713aSLionel Sambuc case Expr::CXXDependentScopeMemberExprClass:
1093f4a2713aSLionel Sambuc case Expr::CXXUnresolvedConstructExprClass:
1094f4a2713aSLionel Sambuc case Expr::DependentScopeDeclRefExprClass:
1095*0a6a1f1dSLionel Sambuc case Expr::CXXFoldExprClass:
1096f4a2713aSLionel Sambuc return CT_Dependent;
1097f4a2713aSLionel Sambuc
1098f4a2713aSLionel Sambuc case Expr::AsTypeExprClass:
1099f4a2713aSLionel Sambuc case Expr::BinaryConditionalOperatorClass:
1100f4a2713aSLionel Sambuc case Expr::BlockExprClass:
1101f4a2713aSLionel Sambuc case Expr::CUDAKernelCallExprClass:
1102f4a2713aSLionel Sambuc case Expr::DeclRefExprClass:
1103f4a2713aSLionel Sambuc case Expr::ObjCBridgedCastExprClass:
1104f4a2713aSLionel Sambuc case Expr::ObjCIndirectCopyRestoreExprClass:
1105f4a2713aSLionel Sambuc case Expr::ObjCProtocolExprClass:
1106f4a2713aSLionel Sambuc case Expr::ObjCSelectorExprClass:
1107f4a2713aSLionel Sambuc case Expr::OffsetOfExprClass:
1108f4a2713aSLionel Sambuc case Expr::PackExpansionExprClass:
1109f4a2713aSLionel Sambuc case Expr::PseudoObjectExprClass:
1110f4a2713aSLionel Sambuc case Expr::SubstNonTypeTemplateParmExprClass:
1111f4a2713aSLionel Sambuc case Expr::SubstNonTypeTemplateParmPackExprClass:
1112f4a2713aSLionel Sambuc case Expr::FunctionParmPackExprClass:
1113f4a2713aSLionel Sambuc case Expr::UnaryExprOrTypeTraitExprClass:
1114f4a2713aSLionel Sambuc case Expr::UnresolvedLookupExprClass:
1115f4a2713aSLionel Sambuc case Expr::UnresolvedMemberExprClass:
1116*0a6a1f1dSLionel Sambuc case Expr::TypoExprClass:
1117f4a2713aSLionel Sambuc // FIXME: Can any of the above throw? If so, when?
1118f4a2713aSLionel Sambuc return CT_Cannot;
1119f4a2713aSLionel Sambuc
1120f4a2713aSLionel Sambuc case Expr::AddrLabelExprClass:
1121f4a2713aSLionel Sambuc case Expr::ArrayTypeTraitExprClass:
1122f4a2713aSLionel Sambuc case Expr::AtomicExprClass:
1123f4a2713aSLionel Sambuc case Expr::TypeTraitExprClass:
1124f4a2713aSLionel Sambuc case Expr::CXXBoolLiteralExprClass:
1125f4a2713aSLionel Sambuc case Expr::CXXNoexceptExprClass:
1126f4a2713aSLionel Sambuc case Expr::CXXNullPtrLiteralExprClass:
1127f4a2713aSLionel Sambuc case Expr::CXXPseudoDestructorExprClass:
1128f4a2713aSLionel Sambuc case Expr::CXXScalarValueInitExprClass:
1129f4a2713aSLionel Sambuc case Expr::CXXThisExprClass:
1130f4a2713aSLionel Sambuc case Expr::CXXUuidofExprClass:
1131f4a2713aSLionel Sambuc case Expr::CharacterLiteralClass:
1132f4a2713aSLionel Sambuc case Expr::ExpressionTraitExprClass:
1133f4a2713aSLionel Sambuc case Expr::FloatingLiteralClass:
1134f4a2713aSLionel Sambuc case Expr::GNUNullExprClass:
1135f4a2713aSLionel Sambuc case Expr::ImaginaryLiteralClass:
1136f4a2713aSLionel Sambuc case Expr::ImplicitValueInitExprClass:
1137f4a2713aSLionel Sambuc case Expr::IntegerLiteralClass:
1138f4a2713aSLionel Sambuc case Expr::ObjCEncodeExprClass:
1139f4a2713aSLionel Sambuc case Expr::ObjCStringLiteralClass:
1140f4a2713aSLionel Sambuc case Expr::ObjCBoolLiteralExprClass:
1141f4a2713aSLionel Sambuc case Expr::OpaqueValueExprClass:
1142f4a2713aSLionel Sambuc case Expr::PredefinedExprClass:
1143f4a2713aSLionel Sambuc case Expr::SizeOfPackExprClass:
1144f4a2713aSLionel Sambuc case Expr::StringLiteralClass:
1145f4a2713aSLionel Sambuc // These expressions can never throw.
1146f4a2713aSLionel Sambuc return CT_Cannot;
1147f4a2713aSLionel Sambuc
1148f4a2713aSLionel Sambuc case Expr::MSPropertyRefExprClass:
1149f4a2713aSLionel Sambuc llvm_unreachable("Invalid class for expression");
1150f4a2713aSLionel Sambuc
1151f4a2713aSLionel Sambuc #define STMT(CLASS, PARENT) case Expr::CLASS##Class:
1152f4a2713aSLionel Sambuc #define STMT_RANGE(Base, First, Last)
1153f4a2713aSLionel Sambuc #define LAST_STMT_RANGE(BASE, FIRST, LAST)
1154f4a2713aSLionel Sambuc #define EXPR(CLASS, PARENT)
1155f4a2713aSLionel Sambuc #define ABSTRACT_STMT(STMT)
1156f4a2713aSLionel Sambuc #include "clang/AST/StmtNodes.inc"
1157f4a2713aSLionel Sambuc case Expr::NoStmtClass:
1158f4a2713aSLionel Sambuc llvm_unreachable("Invalid class for expression");
1159f4a2713aSLionel Sambuc }
1160f4a2713aSLionel Sambuc llvm_unreachable("Bogus StmtClass");
1161f4a2713aSLionel Sambuc }
1162f4a2713aSLionel Sambuc
1163f4a2713aSLionel Sambuc } // end namespace clang
1164