xref: /minix3/external/bsd/llvm/dist/clang/lib/Sema/SemaExceptionSpec.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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