1198092Srdivacky//===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===//
2198092Srdivacky//
3198092Srdivacky//                     The LLVM Compiler Infrastructure
4198092Srdivacky//
5198092Srdivacky// This file is distributed under the University of Illinois Open Source
6198092Srdivacky// License. See LICENSE.TXT for details.
7198092Srdivacky//
8198092Srdivacky//===----------------------------------------------------------------------===//
9198092Srdivacky//
10198092Srdivacky// This file provides Sema routines for C++ exception specification testing.
11198092Srdivacky//
12198092Srdivacky//===----------------------------------------------------------------------===//
13198092Srdivacky
14212904Sdim#include "clang/Sema/SemaInternal.h"
15198092Srdivacky#include "clang/AST/CXXInheritance.h"
16198092Srdivacky#include "clang/AST/Expr.h"
17198092Srdivacky#include "clang/AST/ExprCXX.h"
18206084Srdivacky#include "clang/AST/TypeLoc.h"
19203955Srdivacky#include "clang/Basic/Diagnostic.h"
20203955Srdivacky#include "clang/Basic/SourceManager.h"
21249423Sdim#include "clang/Lex/Preprocessor.h"
22198092Srdivacky#include "llvm/ADT/SmallPtrSet.h"
23234353Sdim#include "llvm/ADT/SmallString.h"
24198092Srdivacky
25198092Srdivackynamespace clang {
26198092Srdivacky
27198092Srdivackystatic const FunctionProtoType *GetUnderlyingFunction(QualType T)
28198092Srdivacky{
29198092Srdivacky  if (const PointerType *PtrTy = T->getAs<PointerType>())
30198092Srdivacky    T = PtrTy->getPointeeType();
31198092Srdivacky  else if (const ReferenceType *RefTy = T->getAs<ReferenceType>())
32198092Srdivacky    T = RefTy->getPointeeType();
33198092Srdivacky  else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>())
34198092Srdivacky    T = MPTy->getPointeeType();
35198092Srdivacky  return T->getAs<FunctionProtoType>();
36198092Srdivacky}
37198092Srdivacky
38198092Srdivacky/// CheckSpecifiedExceptionType - Check if the given type is valid in an
39198092Srdivacky/// exception specification. Incomplete types, or pointers to incomplete types
40198092Srdivacky/// other than void are not allowed.
41249423Sdim///
42249423Sdim/// \param[in,out] T  The exception type. This will be decayed to a pointer type
43249423Sdim///                   when the input is an array or a function type.
44249423Sdimbool Sema::CheckSpecifiedExceptionType(QualType &T, const SourceRange &Range) {
45249423Sdim  // C++11 [except.spec]p2:
46249423Sdim  //   A type cv T, "array of T", or "function returning T" denoted
47249423Sdim  //   in an exception-specification is adjusted to type T, "pointer to T", or
48249423Sdim  //   "pointer to function returning T", respectively.
49249423Sdim  //
50249423Sdim  // We also apply this rule in C++98.
51249423Sdim  if (T->isArrayType())
52249423Sdim    T = Context.getArrayDecayedType(T);
53249423Sdim  else if (T->isFunctionType())
54249423Sdim    T = Context.getPointerType(T);
55198092Srdivacky
56249423Sdim  int Kind = 0;
57249423Sdim  QualType PointeeT = T;
58249423Sdim  if (const PointerType *PT = T->getAs<PointerType>()) {
59249423Sdim    PointeeT = PT->getPointeeType();
60249423Sdim    Kind = 1;
61198092Srdivacky
62249423Sdim    // cv void* is explicitly permitted, despite being a pointer to an
63249423Sdim    // incomplete type.
64249423Sdim    if (PointeeT->isVoidType())
65249423Sdim      return false;
66249423Sdim  } else if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
67249423Sdim    PointeeT = RT->getPointeeType();
68249423Sdim    Kind = 2;
69198092Srdivacky
70249423Sdim    if (RT->isRValueReferenceType()) {
71249423Sdim      // C++11 [except.spec]p2:
72249423Sdim      //   A type denoted in an exception-specification shall not denote [...]
73249423Sdim      //   an rvalue reference type.
74249423Sdim      Diag(Range.getBegin(), diag::err_rref_in_exception_spec)
75249423Sdim        << T << Range;
76249423Sdim      return true;
77249423Sdim    }
78249423Sdim  }
79249423Sdim
80249423Sdim  // C++11 [except.spec]p2:
81249423Sdim  //   A type denoted in an exception-specification shall not denote an
82249423Sdim  //   incomplete type other than a class currently being defined [...].
83249423Sdim  //   A type denoted in an exception-specification shall not denote a
84249423Sdim  //   pointer or reference to an incomplete type, other than (cv) void* or a
85249423Sdim  //   pointer or reference to a class currently being defined.
86249423Sdim  if (!(PointeeT->isRecordType() &&
87249423Sdim        PointeeT->getAs<RecordType>()->isBeingDefined()) &&
88249423Sdim      RequireCompleteType(Range.getBegin(), PointeeT,
89249423Sdim                          diag::err_incomplete_in_exception_spec, Kind, Range))
90198092Srdivacky    return true;
91198092Srdivacky
92198092Srdivacky  return false;
93198092Srdivacky}
94198092Srdivacky
95198092Srdivacky/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
96198092Srdivacky/// to member to a function with an exception specification. This means that
97198092Srdivacky/// it is invalid to add another level of indirection.
98198092Srdivackybool Sema::CheckDistantExceptionSpec(QualType T) {
99198092Srdivacky  if (const PointerType *PT = T->getAs<PointerType>())
100198092Srdivacky    T = PT->getPointeeType();
101198092Srdivacky  else if (const MemberPointerType *PT = T->getAs<MemberPointerType>())
102198092Srdivacky    T = PT->getPointeeType();
103198092Srdivacky  else
104198092Srdivacky    return false;
105198092Srdivacky
106198092Srdivacky  const FunctionProtoType *FnT = T->getAs<FunctionProtoType>();
107198092Srdivacky  if (!FnT)
108198092Srdivacky    return false;
109198092Srdivacky
110198092Srdivacky  return FnT->hasExceptionSpec();
111198092Srdivacky}
112198092Srdivacky
113234982Sdimconst FunctionProtoType *
114234982SdimSema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
115239462Sdim  if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
116234982Sdim    return FPT;
117234982Sdim
118234982Sdim  FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl();
119234982Sdim  const FunctionProtoType *SourceFPT =
120234982Sdim      SourceDecl->getType()->castAs<FunctionProtoType>();
121234982Sdim
122239462Sdim  // If the exception specification has already been resolved, just return it.
123239462Sdim  if (!isUnresolvedExceptionSpec(SourceFPT->getExceptionSpecType()))
124234982Sdim    return SourceFPT;
125234982Sdim
126239462Sdim  // Compute or instantiate the exception specification now.
127249423Sdim  if (SourceFPT->getExceptionSpecType() == EST_Unevaluated)
128239462Sdim    EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl));
129239462Sdim  else
130239462Sdim    InstantiateExceptionSpec(Loc, SourceDecl);
131234982Sdim
132234982Sdim  return SourceDecl->getType()->castAs<FunctionProtoType>();
133234982Sdim}
134234982Sdim
135243830Sdim/// Determine whether a function has an implicitly-generated exception
136243830Sdim/// specification.
137243830Sdimstatic bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
138243830Sdim  if (!isa<CXXDestructorDecl>(Decl) &&
139243830Sdim      Decl->getDeclName().getCXXOverloadedOperator() != OO_Delete &&
140243830Sdim      Decl->getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
141243830Sdim    return false;
142243830Sdim
143243830Sdim  // If the user didn't declare the function, its exception specification must
144243830Sdim  // be implicit.
145243830Sdim  if (!Decl->getTypeSourceInfo())
146243830Sdim    return true;
147243830Sdim
148243830Sdim  const FunctionProtoType *Ty =
149243830Sdim    Decl->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>();
150243830Sdim  return !Ty->hasExceptionSpec();
151243830Sdim}
152243830Sdim
153203955Srdivackybool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
154221345Sdim  OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator();
155221345Sdim  bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;
156206084Srdivacky  bool MissingExceptionSpecification = false;
157203955Srdivacky  bool MissingEmptyExceptionSpecification = false;
158221345Sdim  unsigned DiagID = diag::err_mismatched_exception_spec;
159234353Sdim  if (getLangOpts().MicrosoftExt)
160221345Sdim    DiagID = diag::warn_mismatched_exception_spec;
161234982Sdim
162243830Sdim  // Check the types as written: they must match before any exception
163243830Sdim  // specification adjustment is applied.
164243830Sdim  if (!CheckEquivalentExceptionSpec(
165243830Sdim        PDiag(DiagID), PDiag(diag::note_previous_declaration),
166243830Sdim        Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
167243830Sdim        New->getType()->getAs<FunctionProtoType>(), New->getLocation(),
168243830Sdim        &MissingExceptionSpecification, &MissingEmptyExceptionSpecification,
169243830Sdim        /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) {
170243830Sdim    // C++11 [except.spec]p4 [DR1492]:
171243830Sdim    //   If a declaration of a function has an implicit
172243830Sdim    //   exception-specification, other declarations of the function shall
173243830Sdim    //   not specify an exception-specification.
174249423Sdim    if (getLangOpts().CPlusPlus11 &&
175243830Sdim        hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) {
176243830Sdim      Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch)
177243830Sdim        << hasImplicitExceptionSpec(Old);
178243830Sdim      if (!Old->getLocation().isInvalid())
179243830Sdim        Diag(Old->getLocation(), diag::note_previous_declaration);
180243830Sdim    }
181203955Srdivacky    return false;
182243830Sdim  }
183203955Srdivacky
184203955Srdivacky  // The failure was something other than an empty exception
185203955Srdivacky  // specification; return an error.
186206084Srdivacky  if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification)
187203955Srdivacky    return true;
188203955Srdivacky
189243830Sdim  const FunctionProtoType *NewProto =
190243830Sdim    New->getType()->getAs<FunctionProtoType>();
191218893Sdim
192203955Srdivacky  // The new function declaration is only missing an empty exception
193203955Srdivacky  // specification "throw()". If the throw() specification came from a
194203955Srdivacky  // function in a system header that has C linkage, just add an empty
195203955Srdivacky  // exception specification to the "new" declaration. This is an
196203955Srdivacky  // egregious workaround for glibc, which adds throw() specifications
197203955Srdivacky  // to many libc functions as an optimization. Unfortunately, that
198203955Srdivacky  // optimization isn't permitted by the C++ standard, so we're forced
199203955Srdivacky  // to work around it here.
200218893Sdim  if (MissingEmptyExceptionSpecification && NewProto &&
201206084Srdivacky      (Old->getLocation().isInvalid() ||
202206084Srdivacky       Context.getSourceManager().isInSystemHeader(Old->getLocation())) &&
203203955Srdivacky      Old->isExternC()) {
204218893Sdim    FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
205221345Sdim    EPI.ExceptionSpecType = EST_DynamicNone;
206249423Sdim    QualType NewType =
207249423Sdim      Context.getFunctionType(NewProto->getResultType(),
208249423Sdim                              ArrayRef<QualType>(NewProto->arg_type_begin(),
209249423Sdim                                                 NewProto->getNumArgs()),
210249423Sdim                              EPI);
211203955Srdivacky    New->setType(NewType);
212203955Srdivacky    return false;
213203955Srdivacky  }
214203955Srdivacky
215218893Sdim  if (MissingExceptionSpecification && NewProto) {
216243830Sdim    const FunctionProtoType *OldProto =
217243830Sdim      Old->getType()->getAs<FunctionProtoType>();
218206084Srdivacky
219218893Sdim    FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
220221345Sdim    EPI.ExceptionSpecType = OldProto->getExceptionSpecType();
221221345Sdim    if (EPI.ExceptionSpecType == EST_Dynamic) {
222221345Sdim      EPI.NumExceptions = OldProto->getNumExceptions();
223221345Sdim      EPI.Exceptions = OldProto->exception_begin();
224221345Sdim    } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
225221345Sdim      // FIXME: We can't just take the expression from the old prototype. It
226221345Sdim      // likely contains references to the old prototype's parameters.
227221345Sdim    }
228218893Sdim
229206084Srdivacky    // Update the type of the function with the appropriate exception
230206084Srdivacky    // specification.
231249423Sdim    QualType NewType =
232249423Sdim      Context.getFunctionType(NewProto->getResultType(),
233249423Sdim                              ArrayRef<QualType>(NewProto->arg_type_begin(),
234249423Sdim                                                 NewProto->getNumArgs()),
235249423Sdim                              EPI);
236206084Srdivacky    New->setType(NewType);
237206084Srdivacky
238206084Srdivacky    // If exceptions are disabled, suppress the warning about missing
239206084Srdivacky    // exception specifications for new and delete operators.
240234353Sdim    if (!getLangOpts().CXXExceptions) {
241206084Srdivacky      switch (New->getDeclName().getCXXOverloadedOperator()) {
242206084Srdivacky      case OO_New:
243206084Srdivacky      case OO_Array_New:
244206084Srdivacky      case OO_Delete:
245206084Srdivacky      case OO_Array_Delete:
246206084Srdivacky        if (New->getDeclContext()->isTranslationUnit())
247206084Srdivacky          return false;
248206084Srdivacky        break;
249206084Srdivacky
250206084Srdivacky      default:
251206084Srdivacky        break;
252206084Srdivacky      }
253206084Srdivacky    }
254206084Srdivacky
255206084Srdivacky    // Warn about the lack of exception specification.
256234353Sdim    SmallString<128> ExceptionSpecString;
257206084Srdivacky    llvm::raw_svector_ostream OS(ExceptionSpecString);
258221345Sdim    switch (OldProto->getExceptionSpecType()) {
259221345Sdim    case EST_DynamicNone:
260221345Sdim      OS << "throw()";
261221345Sdim      break;
262221345Sdim
263221345Sdim    case EST_Dynamic: {
264221345Sdim      OS << "throw(";
265221345Sdim      bool OnFirstException = true;
266221345Sdim      for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(),
267221345Sdim                                              EEnd = OldProto->exception_end();
268221345Sdim           E != EEnd;
269221345Sdim           ++E) {
270221345Sdim        if (OnFirstException)
271221345Sdim          OnFirstException = false;
272221345Sdim        else
273221345Sdim          OS << ", ";
274221345Sdim
275226633Sdim        OS << E->getAsString(getPrintingPolicy());
276221345Sdim      }
277221345Sdim      OS << ")";
278221345Sdim      break;
279206084Srdivacky    }
280221345Sdim
281221345Sdim    case EST_BasicNoexcept:
282221345Sdim      OS << "noexcept";
283221345Sdim      break;
284221345Sdim
285221345Sdim    case EST_ComputedNoexcept:
286221345Sdim      OS << "noexcept(";
287239462Sdim      OldProto->getNoexceptExpr()->printPretty(OS, 0, getPrintingPolicy());
288221345Sdim      OS << ")";
289221345Sdim      break;
290221345Sdim
291221345Sdim    default:
292226633Sdim      llvm_unreachable("This spec type is compatible with none.");
293221345Sdim    }
294206084Srdivacky    OS.flush();
295206084Srdivacky
296221345Sdim    SourceLocation FixItLoc;
297206084Srdivacky    if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) {
298218893Sdim      TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();
299249423Sdim      if (FunctionTypeLoc FTLoc = TL.getAs<FunctionTypeLoc>())
300249423Sdim        FixItLoc = PP.getLocForEndOfToken(FTLoc.getLocalRangeEnd());
301206084Srdivacky    }
302206084Srdivacky
303221345Sdim    if (FixItLoc.isInvalid())
304206084Srdivacky      Diag(New->getLocation(), diag::warn_missing_exception_specification)
305206084Srdivacky        << New << OS.str();
306206084Srdivacky    else {
307206084Srdivacky      // FIXME: This will get more complicated with C++0x
308206084Srdivacky      // late-specified return types.
309206084Srdivacky      Diag(New->getLocation(), diag::warn_missing_exception_specification)
310206084Srdivacky        << New << OS.str()
311221345Sdim        << FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str());
312206084Srdivacky    }
313206084Srdivacky
314206084Srdivacky    if (!Old->getLocation().isInvalid())
315206084Srdivacky      Diag(Old->getLocation(), diag::note_previous_declaration);
316206084Srdivacky
317206084Srdivacky    return false;
318206084Srdivacky  }
319206084Srdivacky
320221345Sdim  Diag(New->getLocation(), DiagID);
321203955Srdivacky  Diag(Old->getLocation(), diag::note_previous_declaration);
322203955Srdivacky  return true;
323203955Srdivacky}
324203955Srdivacky
325198092Srdivacky/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
326198092Srdivacky/// exception specifications. Exception specifications are equivalent if
327198092Srdivacky/// they allow exactly the same set of exception types. It does not matter how
328198092Srdivacky/// that is achieved. See C++ [except.spec]p2.
329198092Srdivackybool Sema::CheckEquivalentExceptionSpec(
330198092Srdivacky    const FunctionProtoType *Old, SourceLocation OldLoc,
331198092Srdivacky    const FunctionProtoType *New, SourceLocation NewLoc) {
332221345Sdim  unsigned DiagID = diag::err_mismatched_exception_spec;
333234353Sdim  if (getLangOpts().MicrosoftExt)
334221345Sdim    DiagID = diag::warn_mismatched_exception_spec;
335243830Sdim  return CheckEquivalentExceptionSpec(PDiag(DiagID),
336206084Srdivacky                                      PDiag(diag::note_previous_declaration),
337198092Srdivacky                                      Old, OldLoc, New, NewLoc);
338198092Srdivacky}
339198092Srdivacky
340221345Sdim/// CheckEquivalentExceptionSpec - Check if the two types have compatible
341221345Sdim/// exception specifications. See C++ [except.spec]p3.
342243830Sdim///
343243830Sdim/// \return \c false if the exception specifications match, \c true if there is
344243830Sdim/// a problem. If \c true is returned, either a diagnostic has already been
345243830Sdim/// produced or \c *MissingExceptionSpecification is set to \c true.
346221345Sdimbool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
347206084Srdivacky                                        const PartialDiagnostic & NoteID,
348221345Sdim                                        const FunctionProtoType *Old,
349206084Srdivacky                                        SourceLocation OldLoc,
350221345Sdim                                        const FunctionProtoType *New,
351206084Srdivacky                                        SourceLocation NewLoc,
352206084Srdivacky                                        bool *MissingExceptionSpecification,
353221345Sdim                                        bool*MissingEmptyExceptionSpecification,
354221345Sdim                                        bool AllowNoexceptAllMatchWithNoSpec,
355221345Sdim                                        bool IsOperatorNew) {
356210299Sed  // Just completely ignore this under -fno-exceptions.
357234353Sdim  if (!getLangOpts().CXXExceptions)
358210299Sed    return false;
359210299Sed
360206084Srdivacky  if (MissingExceptionSpecification)
361206084Srdivacky    *MissingExceptionSpecification = false;
362206084Srdivacky
363203955Srdivacky  if (MissingEmptyExceptionSpecification)
364203955Srdivacky    *MissingEmptyExceptionSpecification = false;
365203955Srdivacky
366234982Sdim  Old = ResolveExceptionSpec(NewLoc, Old);
367234982Sdim  if (!Old)
368234982Sdim    return false;
369234982Sdim  New = ResolveExceptionSpec(NewLoc, New);
370234982Sdim  if (!New)
371234982Sdim    return false;
372234982Sdim
373221345Sdim  // C++0x [except.spec]p3: Two exception-specifications are compatible if:
374221345Sdim  //   - both are non-throwing, regardless of their form,
375221345Sdim  //   - both have the form noexcept(constant-expression) and the constant-
376221345Sdim  //     expressions are equivalent,
377221345Sdim  //   - both are dynamic-exception-specifications that have the same set of
378221345Sdim  //     adjusted types.
379221345Sdim  //
380221345Sdim  // C++0x [except.spec]p12: An exception-specifcation is non-throwing if it is
381221345Sdim  //   of the form throw(), noexcept, or noexcept(constant-expression) where the
382221345Sdim  //   constant-expression yields true.
383221345Sdim  //
384221345Sdim  // C++0x [except.spec]p4: If any declaration of a function has an exception-
385221345Sdim  //   specifier that is not a noexcept-specification allowing all exceptions,
386221345Sdim  //   all declarations [...] of that function shall have a compatible
387221345Sdim  //   exception-specification.
388221345Sdim  //
389221345Sdim  // That last point basically means that noexcept(false) matches no spec.
390221345Sdim  // It's considered when AllowNoexceptAllMatchWithNoSpec is true.
391221345Sdim
392221345Sdim  ExceptionSpecificationType OldEST = Old->getExceptionSpecType();
393221345Sdim  ExceptionSpecificationType NewEST = New->getExceptionSpecType();
394221345Sdim
395239462Sdim  assert(!isUnresolvedExceptionSpec(OldEST) &&
396239462Sdim         !isUnresolvedExceptionSpec(NewEST) &&
397223017Sdim         "Shouldn't see unknown exception specifications here");
398223017Sdim
399221345Sdim  // Shortcut the case where both have no spec.
400221345Sdim  if (OldEST == EST_None && NewEST == EST_None)
401221345Sdim    return false;
402221345Sdim
403221345Sdim  FunctionProtoType::NoexceptResult OldNR = Old->getNoexceptSpec(Context);
404221345Sdim  FunctionProtoType::NoexceptResult NewNR = New->getNoexceptSpec(Context);
405221345Sdim  if (OldNR == FunctionProtoType::NR_BadNoexcept ||
406221345Sdim      NewNR == FunctionProtoType::NR_BadNoexcept)
407221345Sdim    return false;
408221345Sdim
409221345Sdim  // Dependent noexcept specifiers are compatible with each other, but nothing
410221345Sdim  // else.
411221345Sdim  // One noexcept is compatible with another if the argument is the same
412221345Sdim  if (OldNR == NewNR &&
413221345Sdim      OldNR != FunctionProtoType::NR_NoNoexcept &&
414221345Sdim      NewNR != FunctionProtoType::NR_NoNoexcept)
415221345Sdim    return false;
416221345Sdim  if (OldNR != NewNR &&
417221345Sdim      OldNR != FunctionProtoType::NR_NoNoexcept &&
418221345Sdim      NewNR != FunctionProtoType::NR_NoNoexcept) {
419221345Sdim    Diag(NewLoc, DiagID);
420221345Sdim    if (NoteID.getDiagID() != 0)
421221345Sdim      Diag(OldLoc, NoteID);
422221345Sdim    return true;
423212904Sdim  }
424212904Sdim
425221345Sdim  // The MS extension throw(...) is compatible with itself.
426221345Sdim  if (OldEST == EST_MSAny && NewEST == EST_MSAny)
427198092Srdivacky    return false;
428221345Sdim
429221345Sdim  // It's also compatible with no spec.
430221345Sdim  if ((OldEST == EST_None && NewEST == EST_MSAny) ||
431221345Sdim      (OldEST == EST_MSAny && NewEST == EST_None))
432221345Sdim    return false;
433221345Sdim
434221345Sdim  // It's also compatible with noexcept(false).
435221345Sdim  if (OldEST == EST_MSAny && NewNR == FunctionProtoType::NR_Throw)
436221345Sdim    return false;
437221345Sdim  if (NewEST == EST_MSAny && OldNR == FunctionProtoType::NR_Throw)
438221345Sdim    return false;
439221345Sdim
440221345Sdim  // As described above, noexcept(false) matches no spec only for functions.
441221345Sdim  if (AllowNoexceptAllMatchWithNoSpec) {
442221345Sdim    if (OldEST == EST_None && NewNR == FunctionProtoType::NR_Throw)
443221345Sdim      return false;
444221345Sdim    if (NewEST == EST_None && OldNR == FunctionProtoType::NR_Throw)
445221345Sdim      return false;
446221345Sdim  }
447221345Sdim
448221345Sdim  // Any non-throwing specifications are compatible.
449221345Sdim  bool OldNonThrowing = OldNR == FunctionProtoType::NR_Nothrow ||
450221345Sdim                        OldEST == EST_DynamicNone;
451221345Sdim  bool NewNonThrowing = NewNR == FunctionProtoType::NR_Nothrow ||
452221345Sdim                        NewEST == EST_DynamicNone;
453221345Sdim  if (OldNonThrowing && NewNonThrowing)
454221345Sdim    return false;
455221345Sdim
456221345Sdim  // As a special compatibility feature, under C++0x we accept no spec and
457221345Sdim  // throw(std::bad_alloc) as equivalent for operator new and operator new[].
458221345Sdim  // This is because the implicit declaration changed, but old code would break.
459249423Sdim  if (getLangOpts().CPlusPlus11 && IsOperatorNew) {
460221345Sdim    const FunctionProtoType *WithExceptions = 0;
461221345Sdim    if (OldEST == EST_None && NewEST == EST_Dynamic)
462221345Sdim      WithExceptions = New;
463221345Sdim    else if (OldEST == EST_Dynamic && NewEST == EST_None)
464221345Sdim      WithExceptions = Old;
465221345Sdim    if (WithExceptions && WithExceptions->getNumExceptions() == 1) {
466221345Sdim      // One has no spec, the other throw(something). If that something is
467221345Sdim      // std::bad_alloc, all conditions are met.
468221345Sdim      QualType Exception = *WithExceptions->exception_begin();
469221345Sdim      if (CXXRecordDecl *ExRecord = Exception->getAsCXXRecordDecl()) {
470221345Sdim        IdentifierInfo* Name = ExRecord->getIdentifier();
471221345Sdim        if (Name && Name->getName() == "bad_alloc") {
472221345Sdim          // It's called bad_alloc, but is it in std?
473221345Sdim          DeclContext* DC = ExRecord->getDeclContext();
474221345Sdim          DC = DC->getEnclosingNamespaceContext();
475221345Sdim          if (NamespaceDecl* NS = dyn_cast<NamespaceDecl>(DC)) {
476221345Sdim            IdentifierInfo* NSName = NS->getIdentifier();
477221345Sdim            DC = DC->getParent();
478221345Sdim            if (NSName && NSName->getName() == "std" &&
479221345Sdim                DC->getEnclosingNamespaceContext()->isTranslationUnit()) {
480221345Sdim              return false;
481221345Sdim            }
482221345Sdim          }
483221345Sdim        }
484221345Sdim      }
485221345Sdim    }
486221345Sdim  }
487221345Sdim
488221345Sdim  // At this point, the only remaining valid case is two matching dynamic
489221345Sdim  // specifications. We return here unless both specifications are dynamic.
490221345Sdim  if (OldEST != EST_Dynamic || NewEST != EST_Dynamic) {
491206084Srdivacky    if (MissingExceptionSpecification && Old->hasExceptionSpec() &&
492203955Srdivacky        !New->hasExceptionSpec()) {
493206084Srdivacky      // The old type has an exception specification of some sort, but
494206084Srdivacky      // the new type does not.
495206084Srdivacky      *MissingExceptionSpecification = true;
496206084Srdivacky
497221345Sdim      if (MissingEmptyExceptionSpecification && OldNonThrowing) {
498221345Sdim        // The old type has a throw() or noexcept(true) exception specification
499221345Sdim        // and the new type has no exception specification, and the caller asked
500206084Srdivacky        // to handle this itself.
501206084Srdivacky        *MissingEmptyExceptionSpecification = true;
502206084Srdivacky      }
503206084Srdivacky
504203955Srdivacky      return true;
505203955Srdivacky    }
506203955Srdivacky
507198092Srdivacky    Diag(NewLoc, DiagID);
508198092Srdivacky    if (NoteID.getDiagID() != 0)
509198092Srdivacky      Diag(OldLoc, NoteID);
510198092Srdivacky    return true;
511198092Srdivacky  }
512198092Srdivacky
513221345Sdim  assert(OldEST == EST_Dynamic && NewEST == EST_Dynamic &&
514221345Sdim      "Exception compatibility logic error: non-dynamic spec slipped through.");
515221345Sdim
516198092Srdivacky  bool Success = true;
517221345Sdim  // Both have a dynamic exception spec. Collect the first set, then compare
518198092Srdivacky  // to the second.
519198092Srdivacky  llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes;
520198092Srdivacky  for (FunctionProtoType::exception_iterator I = Old->exception_begin(),
521198092Srdivacky       E = Old->exception_end(); I != E; ++I)
522198092Srdivacky    OldTypes.insert(Context.getCanonicalType(*I).getUnqualifiedType());
523198092Srdivacky
524198092Srdivacky  for (FunctionProtoType::exception_iterator I = New->exception_begin(),
525198092Srdivacky       E = New->exception_end(); I != E && Success; ++I) {
526198092Srdivacky    CanQualType TypePtr = Context.getCanonicalType(*I).getUnqualifiedType();
527198092Srdivacky    if(OldTypes.count(TypePtr))
528198092Srdivacky      NewTypes.insert(TypePtr);
529198092Srdivacky    else
530198092Srdivacky      Success = false;
531198092Srdivacky  }
532198092Srdivacky
533198092Srdivacky  Success = Success && OldTypes.size() == NewTypes.size();
534198092Srdivacky
535198092Srdivacky  if (Success) {
536198092Srdivacky    return false;
537198092Srdivacky  }
538198092Srdivacky  Diag(NewLoc, DiagID);
539198092Srdivacky  if (NoteID.getDiagID() != 0)
540198092Srdivacky    Diag(OldLoc, NoteID);
541198092Srdivacky  return true;
542198092Srdivacky}
543198092Srdivacky
544198092Srdivacky/// CheckExceptionSpecSubset - Check whether the second function type's
545198092Srdivacky/// exception specification is a subset (or equivalent) of the first function
546198092Srdivacky/// type. This is used by override and pointer assignment checks.
547198092Srdivackybool Sema::CheckExceptionSpecSubset(
548198092Srdivacky    const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
549198092Srdivacky    const FunctionProtoType *Superset, SourceLocation SuperLoc,
550198092Srdivacky    const FunctionProtoType *Subset, SourceLocation SubLoc) {
551210299Sed
552210299Sed  // Just auto-succeed under -fno-exceptions.
553234353Sdim  if (!getLangOpts().CXXExceptions)
554210299Sed    return false;
555210299Sed
556198092Srdivacky  // FIXME: As usual, we could be more specific in our error messages, but
557198092Srdivacky  // that better waits until we've got types with source locations.
558198092Srdivacky
559198092Srdivacky  if (!SubLoc.isValid())
560198092Srdivacky    SubLoc = SuperLoc;
561198092Srdivacky
562234982Sdim  // Resolve the exception specifications, if needed.
563234982Sdim  Superset = ResolveExceptionSpec(SuperLoc, Superset);
564234982Sdim  if (!Superset)
565234982Sdim    return false;
566234982Sdim  Subset = ResolveExceptionSpec(SubLoc, Subset);
567234982Sdim  if (!Subset)
568234982Sdim    return false;
569234982Sdim
570221345Sdim  ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType();
571221345Sdim
572198092Srdivacky  // If superset contains everything, we're done.
573221345Sdim  if (SuperEST == EST_None || SuperEST == EST_MSAny)
574198092Srdivacky    return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
575198092Srdivacky
576221345Sdim  // If there are dependent noexcept specs, assume everything is fine. Unlike
577221345Sdim  // with the equivalency check, this is safe in this case, because we don't
578221345Sdim  // want to merge declarations. Checks after instantiation will catch any
579221345Sdim  // omissions we make here.
580221345Sdim  // We also shortcut checking if a noexcept expression was bad.
581221345Sdim
582221345Sdim  FunctionProtoType::NoexceptResult SuperNR =Superset->getNoexceptSpec(Context);
583221345Sdim  if (SuperNR == FunctionProtoType::NR_BadNoexcept ||
584221345Sdim      SuperNR == FunctionProtoType::NR_Dependent)
585221345Sdim    return false;
586221345Sdim
587221345Sdim  // Another case of the superset containing everything.
588221345Sdim  if (SuperNR == FunctionProtoType::NR_Throw)
589221345Sdim    return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
590221345Sdim
591221345Sdim  ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
592221345Sdim
593239462Sdim  assert(!isUnresolvedExceptionSpec(SuperEST) &&
594239462Sdim         !isUnresolvedExceptionSpec(SubEST) &&
595223017Sdim         "Shouldn't see unknown exception specifications here");
596223017Sdim
597198092Srdivacky  // It does not. If the subset contains everything, we've failed.
598221345Sdim  if (SubEST == EST_None || SubEST == EST_MSAny) {
599198092Srdivacky    Diag(SubLoc, DiagID);
600198092Srdivacky    if (NoteID.getDiagID() != 0)
601198092Srdivacky      Diag(SuperLoc, NoteID);
602198092Srdivacky    return true;
603198092Srdivacky  }
604198092Srdivacky
605221345Sdim  FunctionProtoType::NoexceptResult SubNR = Subset->getNoexceptSpec(Context);
606221345Sdim  if (SubNR == FunctionProtoType::NR_BadNoexcept ||
607221345Sdim      SubNR == FunctionProtoType::NR_Dependent)
608221345Sdim    return false;
609221345Sdim
610221345Sdim  // Another case of the subset containing everything.
611221345Sdim  if (SubNR == FunctionProtoType::NR_Throw) {
612221345Sdim    Diag(SubLoc, DiagID);
613221345Sdim    if (NoteID.getDiagID() != 0)
614221345Sdim      Diag(SuperLoc, NoteID);
615221345Sdim    return true;
616221345Sdim  }
617221345Sdim
618221345Sdim  // If the subset contains nothing, we're done.
619221345Sdim  if (SubEST == EST_DynamicNone || SubNR == FunctionProtoType::NR_Nothrow)
620221345Sdim    return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
621221345Sdim
622221345Sdim  // Otherwise, if the superset contains nothing, we've failed.
623221345Sdim  if (SuperEST == EST_DynamicNone || SuperNR == FunctionProtoType::NR_Nothrow) {
624221345Sdim    Diag(SubLoc, DiagID);
625221345Sdim    if (NoteID.getDiagID() != 0)
626221345Sdim      Diag(SuperLoc, NoteID);
627221345Sdim    return true;
628221345Sdim  }
629221345Sdim
630221345Sdim  assert(SuperEST == EST_Dynamic && SubEST == EST_Dynamic &&
631221345Sdim         "Exception spec subset: non-dynamic case slipped through.");
632221345Sdim
633221345Sdim  // Neither contains everything or nothing. Do a proper comparison.
634198092Srdivacky  for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(),
635198092Srdivacky       SubE = Subset->exception_end(); SubI != SubE; ++SubI) {
636198092Srdivacky    // Take one type from the subset.
637198092Srdivacky    QualType CanonicalSubT = Context.getCanonicalType(*SubI);
638198092Srdivacky    // Unwrap pointers and references so that we can do checks within a class
639198092Srdivacky    // hierarchy. Don't unwrap member pointers; they don't have hierarchy
640198092Srdivacky    // conversions on the pointee.
641198092Srdivacky    bool SubIsPointer = false;
642198092Srdivacky    if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>())
643198092Srdivacky      CanonicalSubT = RefTy->getPointeeType();
644198092Srdivacky    if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) {
645198092Srdivacky      CanonicalSubT = PtrTy->getPointeeType();
646198092Srdivacky      SubIsPointer = true;
647198092Srdivacky    }
648198092Srdivacky    bool SubIsClass = CanonicalSubT->isRecordType();
649199482Srdivacky    CanonicalSubT = CanonicalSubT.getLocalUnqualifiedType();
650198092Srdivacky
651198092Srdivacky    CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
652198092Srdivacky                       /*DetectVirtual=*/false);
653198092Srdivacky
654198092Srdivacky    bool Contained = false;
655198092Srdivacky    // Make sure it's in the superset.
656198092Srdivacky    for (FunctionProtoType::exception_iterator SuperI =
657198092Srdivacky           Superset->exception_begin(), SuperE = Superset->exception_end();
658198092Srdivacky         SuperI != SuperE; ++SuperI) {
659198092Srdivacky      QualType CanonicalSuperT = Context.getCanonicalType(*SuperI);
660198092Srdivacky      // SubT must be SuperT or derived from it, or pointer or reference to
661198092Srdivacky      // such types.
662198092Srdivacky      if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>())
663198092Srdivacky        CanonicalSuperT = RefTy->getPointeeType();
664198092Srdivacky      if (SubIsPointer) {
665198092Srdivacky        if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>())
666198092Srdivacky          CanonicalSuperT = PtrTy->getPointeeType();
667198092Srdivacky        else {
668198092Srdivacky          continue;
669198092Srdivacky        }
670198092Srdivacky      }
671199482Srdivacky      CanonicalSuperT = CanonicalSuperT.getLocalUnqualifiedType();
672198092Srdivacky      // If the types are the same, move on to the next type in the subset.
673198092Srdivacky      if (CanonicalSubT == CanonicalSuperT) {
674198092Srdivacky        Contained = true;
675198092Srdivacky        break;
676198092Srdivacky      }
677198092Srdivacky
678198092Srdivacky      // Otherwise we need to check the inheritance.
679198092Srdivacky      if (!SubIsClass || !CanonicalSuperT->isRecordType())
680198092Srdivacky        continue;
681198092Srdivacky
682198092Srdivacky      Paths.clear();
683198092Srdivacky      if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths))
684198092Srdivacky        continue;
685198092Srdivacky
686208600Srdivacky      if (Paths.isAmbiguous(Context.getCanonicalType(CanonicalSuperT)))
687198092Srdivacky        continue;
688198092Srdivacky
689203955Srdivacky      // Do this check from a context without privileges.
690205219Srdivacky      switch (CheckBaseClassAccess(SourceLocation(),
691203955Srdivacky                                   CanonicalSuperT, CanonicalSubT,
692203955Srdivacky                                   Paths.front(),
693205219Srdivacky                                   /*Diagnostic*/ 0,
694203955Srdivacky                                   /*ForceCheck*/ true,
695205219Srdivacky                                   /*ForceUnprivileged*/ true)) {
696203955Srdivacky      case AR_accessible: break;
697203955Srdivacky      case AR_inaccessible: continue;
698203955Srdivacky      case AR_dependent:
699203955Srdivacky        llvm_unreachable("access check dependent for unprivileged context");
700203955Srdivacky      case AR_delayed:
701203955Srdivacky        llvm_unreachable("access check delayed in non-declaration");
702203955Srdivacky      }
703198092Srdivacky
704198092Srdivacky      Contained = true;
705198092Srdivacky      break;
706198092Srdivacky    }
707198092Srdivacky    if (!Contained) {
708198092Srdivacky      Diag(SubLoc, DiagID);
709198092Srdivacky      if (NoteID.getDiagID() != 0)
710198092Srdivacky        Diag(SuperLoc, NoteID);
711198092Srdivacky      return true;
712198092Srdivacky    }
713198092Srdivacky  }
714198092Srdivacky  // We've run half the gauntlet.
715198092Srdivacky  return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
716198092Srdivacky}
717198092Srdivacky
718198092Srdivackystatic bool CheckSpecForTypesEquivalent(Sema &S,
719198092Srdivacky    const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
720198092Srdivacky    QualType Target, SourceLocation TargetLoc,
721198092Srdivacky    QualType Source, SourceLocation SourceLoc)
722198092Srdivacky{
723198092Srdivacky  const FunctionProtoType *TFunc = GetUnderlyingFunction(Target);
724198092Srdivacky  if (!TFunc)
725198092Srdivacky    return false;
726198092Srdivacky  const FunctionProtoType *SFunc = GetUnderlyingFunction(Source);
727198092Srdivacky  if (!SFunc)
728198092Srdivacky    return false;
729198092Srdivacky
730198092Srdivacky  return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc,
731198092Srdivacky                                        SFunc, SourceLoc);
732198092Srdivacky}
733198092Srdivacky
734198092Srdivacky/// CheckParamExceptionSpec - Check if the parameter and return types of the
735198092Srdivacky/// two functions have equivalent exception specs. This is part of the
736198092Srdivacky/// assignment and override compatibility check. We do not check the parameters
737198092Srdivacky/// of parameter function pointers recursively, as no sane programmer would
738198092Srdivacky/// even be able to write such a function type.
739198092Srdivackybool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
740198092Srdivacky    const FunctionProtoType *Target, SourceLocation TargetLoc,
741198092Srdivacky    const FunctionProtoType *Source, SourceLocation SourceLoc)
742198092Srdivacky{
743198092Srdivacky  if (CheckSpecForTypesEquivalent(*this,
744206084Srdivacky                           PDiag(diag::err_deep_exception_specs_differ) << 0,
745206084Srdivacky                                  PDiag(),
746198092Srdivacky                                  Target->getResultType(), TargetLoc,
747198092Srdivacky                                  Source->getResultType(), SourceLoc))
748198092Srdivacky    return true;
749198092Srdivacky
750198092Srdivacky  // We shouldn't even be testing this unless the arguments are otherwise
751198092Srdivacky  // compatible.
752198092Srdivacky  assert(Target->getNumArgs() == Source->getNumArgs() &&
753198092Srdivacky         "Functions have different argument counts.");
754198092Srdivacky  for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) {
755198092Srdivacky    if (CheckSpecForTypesEquivalent(*this,
756206084Srdivacky                           PDiag(diag::err_deep_exception_specs_differ) << 1,
757206084Srdivacky                                    PDiag(),
758198092Srdivacky                                    Target->getArgType(i), TargetLoc,
759198092Srdivacky                                    Source->getArgType(i), SourceLoc))
760198092Srdivacky      return true;
761198092Srdivacky  }
762198092Srdivacky  return false;
763198092Srdivacky}
764198092Srdivacky
765198092Srdivackybool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
766198092Srdivacky{
767198092Srdivacky  // First we check for applicability.
768198092Srdivacky  // Target type must be a function, function pointer or function reference.
769198092Srdivacky  const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType);
770198092Srdivacky  if (!ToFunc)
771198092Srdivacky    return false;
772198092Srdivacky
773198092Srdivacky  // SourceType must be a function or function pointer.
774198092Srdivacky  const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType());
775198092Srdivacky  if (!FromFunc)
776198092Srdivacky    return false;
777198092Srdivacky
778198092Srdivacky  // Now we've got the correct types on both sides, check their compatibility.
779198092Srdivacky  // This means that the source of the conversion can only throw a subset of
780198092Srdivacky  // the exceptions of the target, and any exception specs on arguments or
781198092Srdivacky  // return types must be equivalent.
782206084Srdivacky  return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs),
783206084Srdivacky                                  PDiag(), ToFunc,
784206084Srdivacky                                  From->getSourceRange().getBegin(),
785198092Srdivacky                                  FromFunc, SourceLocation());
786198092Srdivacky}
787198092Srdivacky
788198092Srdivackybool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
789198092Srdivacky                                                const CXXMethodDecl *Old) {
790249423Sdim  if (getLangOpts().CPlusPlus11 && isa<CXXDestructorDecl>(New)) {
791223017Sdim    // Don't check uninstantiated template destructors at all. We can only
792223017Sdim    // synthesize correct specs after the template is instantiated.
793223017Sdim    if (New->getParent()->isDependentType())
794223017Sdim      return false;
795223017Sdim    if (New->getParent()->isBeingDefined()) {
796223017Sdim      // The destructor might be updated once the definition is finished. So
797223017Sdim      // remember it and check later.
798223017Sdim      DelayedDestructorExceptionSpecChecks.push_back(std::make_pair(
799223017Sdim        cast<CXXDestructorDecl>(New), cast<CXXDestructorDecl>(Old)));
800223017Sdim      return false;
801223017Sdim    }
802223017Sdim  }
803223017Sdim  unsigned DiagID = diag::err_override_exception_spec;
804234353Sdim  if (getLangOpts().MicrosoftExt)
805223017Sdim    DiagID = diag::warn_override_exception_spec;
806223017Sdim  return CheckExceptionSpecSubset(PDiag(DiagID),
807206084Srdivacky                                  PDiag(diag::note_overridden_virtual_function),
808198092Srdivacky                                  Old->getType()->getAs<FunctionProtoType>(),
809198092Srdivacky                                  Old->getLocation(),
810198092Srdivacky                                  New->getType()->getAs<FunctionProtoType>(),
811198092Srdivacky                                  New->getLocation());
812198092Srdivacky}
813198092Srdivacky
814234982Sdimstatic CanThrowResult canSubExprsThrow(Sema &S, const Expr *CE) {
815234982Sdim  Expr *E = const_cast<Expr*>(CE);
816234982Sdim  CanThrowResult R = CT_Cannot;
817234982Sdim  for (Expr::child_range I = E->children(); I && R != CT_Can; ++I)
818234982Sdim    R = mergeCanThrow(R, S.canThrow(cast<Expr>(*I)));
819234982Sdim  return R;
820234982Sdim}
821234982Sdim
822234982Sdimstatic CanThrowResult canCalleeThrow(Sema &S, const Expr *E,
823234982Sdim                                           const Decl *D,
824234982Sdim                                           bool NullThrows = true) {
825234982Sdim  if (!D)
826234982Sdim    return NullThrows ? CT_Can : CT_Cannot;
827234982Sdim
828234982Sdim  // See if we can get a function type from the decl somehow.
829234982Sdim  const ValueDecl *VD = dyn_cast<ValueDecl>(D);
830234982Sdim  if (!VD) // If we have no clue what we're calling, assume the worst.
831234982Sdim    return CT_Can;
832234982Sdim
833234982Sdim  // As an extension, we assume that __attribute__((nothrow)) functions don't
834234982Sdim  // throw.
835234982Sdim  if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
836234982Sdim    return CT_Cannot;
837234982Sdim
838234982Sdim  QualType T = VD->getType();
839234982Sdim  const FunctionProtoType *FT;
840234982Sdim  if ((FT = T->getAs<FunctionProtoType>())) {
841234982Sdim  } else if (const PointerType *PT = T->getAs<PointerType>())
842234982Sdim    FT = PT->getPointeeType()->getAs<FunctionProtoType>();
843234982Sdim  else if (const ReferenceType *RT = T->getAs<ReferenceType>())
844234982Sdim    FT = RT->getPointeeType()->getAs<FunctionProtoType>();
845234982Sdim  else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())
846234982Sdim    FT = MT->getPointeeType()->getAs<FunctionProtoType>();
847234982Sdim  else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())
848234982Sdim    FT = BT->getPointeeType()->getAs<FunctionProtoType>();
849234982Sdim
850234982Sdim  if (!FT)
851234982Sdim    return CT_Can;
852234982Sdim
853234982Sdim  FT = S.ResolveExceptionSpec(E->getLocStart(), FT);
854234982Sdim  if (!FT)
855234982Sdim    return CT_Can;
856234982Sdim
857234982Sdim  return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can;
858234982Sdim}
859234982Sdim
860234982Sdimstatic CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) {
861234982Sdim  if (DC->isTypeDependent())
862234982Sdim    return CT_Dependent;
863234982Sdim
864234982Sdim  if (!DC->getTypeAsWritten()->isReferenceType())
865234982Sdim    return CT_Cannot;
866234982Sdim
867234982Sdim  if (DC->getSubExpr()->isTypeDependent())
868234982Sdim    return CT_Dependent;
869234982Sdim
870234982Sdim  return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot;
871234982Sdim}
872234982Sdim
873234982Sdimstatic CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) {
874234982Sdim  if (DC->isTypeOperand())
875234982Sdim    return CT_Cannot;
876234982Sdim
877234982Sdim  Expr *Op = DC->getExprOperand();
878234982Sdim  if (Op->isTypeDependent())
879234982Sdim    return CT_Dependent;
880234982Sdim
881234982Sdim  const RecordType *RT = Op->getType()->getAs<RecordType>();
882234982Sdim  if (!RT)
883234982Sdim    return CT_Cannot;
884234982Sdim
885234982Sdim  if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())
886234982Sdim    return CT_Cannot;
887234982Sdim
888234982Sdim  if (Op->Classify(S.Context).isPRValue())
889234982Sdim    return CT_Cannot;
890234982Sdim
891234982Sdim  return CT_Can;
892234982Sdim}
893234982Sdim
894234982SdimCanThrowResult Sema::canThrow(const Expr *E) {
895234982Sdim  // C++ [expr.unary.noexcept]p3:
896234982Sdim  //   [Can throw] if in a potentially-evaluated context the expression would
897234982Sdim  //   contain:
898234982Sdim  switch (E->getStmtClass()) {
899234982Sdim  case Expr::CXXThrowExprClass:
900234982Sdim    //   - a potentially evaluated throw-expression
901234982Sdim    return CT_Can;
902234982Sdim
903234982Sdim  case Expr::CXXDynamicCastExprClass: {
904234982Sdim    //   - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),
905234982Sdim    //     where T is a reference type, that requires a run-time check
906234982Sdim    CanThrowResult CT = canDynamicCastThrow(cast<CXXDynamicCastExpr>(E));
907234982Sdim    if (CT == CT_Can)
908234982Sdim      return CT;
909234982Sdim    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
910234982Sdim  }
911234982Sdim
912234982Sdim  case Expr::CXXTypeidExprClass:
913234982Sdim    //   - a potentially evaluated typeid expression applied to a glvalue
914234982Sdim    //     expression whose type is a polymorphic class type
915234982Sdim    return canTypeidThrow(*this, cast<CXXTypeidExpr>(E));
916234982Sdim
917234982Sdim    //   - a potentially evaluated call to a function, member function, function
918234982Sdim    //     pointer, or member function pointer that does not have a non-throwing
919234982Sdim    //     exception-specification
920234982Sdim  case Expr::CallExprClass:
921234982Sdim  case Expr::CXXMemberCallExprClass:
922234982Sdim  case Expr::CXXOperatorCallExprClass:
923234982Sdim  case Expr::UserDefinedLiteralClass: {
924234982Sdim    const CallExpr *CE = cast<CallExpr>(E);
925234982Sdim    CanThrowResult CT;
926234982Sdim    if (E->isTypeDependent())
927234982Sdim      CT = CT_Dependent;
928234982Sdim    else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
929234982Sdim      CT = CT_Cannot;
930234982Sdim    else
931234982Sdim      CT = canCalleeThrow(*this, E, CE->getCalleeDecl());
932234982Sdim    if (CT == CT_Can)
933234982Sdim      return CT;
934234982Sdim    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
935234982Sdim  }
936234982Sdim
937234982Sdim  case Expr::CXXConstructExprClass:
938234982Sdim  case Expr::CXXTemporaryObjectExprClass: {
939234982Sdim    CanThrowResult CT = canCalleeThrow(*this, E,
940234982Sdim        cast<CXXConstructExpr>(E)->getConstructor());
941234982Sdim    if (CT == CT_Can)
942234982Sdim      return CT;
943234982Sdim    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
944234982Sdim  }
945234982Sdim
946234982Sdim  case Expr::LambdaExprClass: {
947234982Sdim    const LambdaExpr *Lambda = cast<LambdaExpr>(E);
948234982Sdim    CanThrowResult CT = CT_Cannot;
949234982Sdim    for (LambdaExpr::capture_init_iterator Cap = Lambda->capture_init_begin(),
950234982Sdim                                        CapEnd = Lambda->capture_init_end();
951234982Sdim         Cap != CapEnd; ++Cap)
952234982Sdim      CT = mergeCanThrow(CT, canThrow(*Cap));
953234982Sdim    return CT;
954234982Sdim  }
955234982Sdim
956234982Sdim  case Expr::CXXNewExprClass: {
957234982Sdim    CanThrowResult CT;
958234982Sdim    if (E->isTypeDependent())
959234982Sdim      CT = CT_Dependent;
960234982Sdim    else
961234982Sdim      CT = canCalleeThrow(*this, E, cast<CXXNewExpr>(E)->getOperatorNew());
962234982Sdim    if (CT == CT_Can)
963234982Sdim      return CT;
964234982Sdim    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
965234982Sdim  }
966234982Sdim
967234982Sdim  case Expr::CXXDeleteExprClass: {
968234982Sdim    CanThrowResult CT;
969234982Sdim    QualType DTy = cast<CXXDeleteExpr>(E)->getDestroyedType();
970234982Sdim    if (DTy.isNull() || DTy->isDependentType()) {
971234982Sdim      CT = CT_Dependent;
972234982Sdim    } else {
973234982Sdim      CT = canCalleeThrow(*this, E,
974234982Sdim                          cast<CXXDeleteExpr>(E)->getOperatorDelete());
975234982Sdim      if (const RecordType *RT = DTy->getAs<RecordType>()) {
976234982Sdim        const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
977234982Sdim        CT = mergeCanThrow(CT, canCalleeThrow(*this, E, RD->getDestructor()));
978234982Sdim      }
979234982Sdim      if (CT == CT_Can)
980234982Sdim        return CT;
981234982Sdim    }
982234982Sdim    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
983234982Sdim  }
984234982Sdim
985234982Sdim  case Expr::CXXBindTemporaryExprClass: {
986234982Sdim    // The bound temporary has to be destroyed again, which might throw.
987234982Sdim    CanThrowResult CT = canCalleeThrow(*this, E,
988234982Sdim      cast<CXXBindTemporaryExpr>(E)->getTemporary()->getDestructor());
989234982Sdim    if (CT == CT_Can)
990234982Sdim      return CT;
991234982Sdim    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
992234982Sdim  }
993234982Sdim
994234982Sdim    // ObjC message sends are like function calls, but never have exception
995234982Sdim    // specs.
996234982Sdim  case Expr::ObjCMessageExprClass:
997234982Sdim  case Expr::ObjCPropertyRefExprClass:
998234982Sdim  case Expr::ObjCSubscriptRefExprClass:
999234982Sdim    return CT_Can;
1000234982Sdim
1001234982Sdim    // All the ObjC literals that are implemented as calls are
1002234982Sdim    // potentially throwing unless we decide to close off that
1003234982Sdim    // possibility.
1004234982Sdim  case Expr::ObjCArrayLiteralClass:
1005234982Sdim  case Expr::ObjCDictionaryLiteralClass:
1006239462Sdim  case Expr::ObjCBoxedExprClass:
1007234982Sdim    return CT_Can;
1008234982Sdim
1009234982Sdim    // Many other things have subexpressions, so we have to test those.
1010234982Sdim    // Some are simple:
1011234982Sdim  case Expr::ConditionalOperatorClass:
1012234982Sdim  case Expr::CompoundLiteralExprClass:
1013234982Sdim  case Expr::CXXConstCastExprClass:
1014234982Sdim  case Expr::CXXReinterpretCastExprClass:
1015234982Sdim  case Expr::DesignatedInitExprClass:
1016234982Sdim  case Expr::ExprWithCleanupsClass:
1017234982Sdim  case Expr::ExtVectorElementExprClass:
1018234982Sdim  case Expr::InitListExprClass:
1019234982Sdim  case Expr::MemberExprClass:
1020234982Sdim  case Expr::ObjCIsaExprClass:
1021234982Sdim  case Expr::ObjCIvarRefExprClass:
1022234982Sdim  case Expr::ParenExprClass:
1023234982Sdim  case Expr::ParenListExprClass:
1024234982Sdim  case Expr::ShuffleVectorExprClass:
1025234982Sdim  case Expr::VAArgExprClass:
1026234982Sdim    return canSubExprsThrow(*this, E);
1027234982Sdim
1028234982Sdim    // Some might be dependent for other reasons.
1029234982Sdim  case Expr::ArraySubscriptExprClass:
1030234982Sdim  case Expr::BinaryOperatorClass:
1031234982Sdim  case Expr::CompoundAssignOperatorClass:
1032234982Sdim  case Expr::CStyleCastExprClass:
1033234982Sdim  case Expr::CXXStaticCastExprClass:
1034234982Sdim  case Expr::CXXFunctionalCastExprClass:
1035234982Sdim  case Expr::ImplicitCastExprClass:
1036234982Sdim  case Expr::MaterializeTemporaryExprClass:
1037234982Sdim  case Expr::UnaryOperatorClass: {
1038234982Sdim    CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot;
1039234982Sdim    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
1040234982Sdim  }
1041234982Sdim
1042234982Sdim    // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms.
1043234982Sdim  case Expr::StmtExprClass:
1044234982Sdim    return CT_Can;
1045234982Sdim
1046251662Sdim  case Expr::CXXDefaultArgExprClass:
1047251662Sdim    return canThrow(cast<CXXDefaultArgExpr>(E)->getExpr());
1048251662Sdim
1049251662Sdim  case Expr::CXXDefaultInitExprClass:
1050251662Sdim    return canThrow(cast<CXXDefaultInitExpr>(E)->getExpr());
1051251662Sdim
1052234982Sdim  case Expr::ChooseExprClass:
1053234982Sdim    if (E->isTypeDependent() || E->isValueDependent())
1054234982Sdim      return CT_Dependent;
1055234982Sdim    return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr(Context));
1056234982Sdim
1057234982Sdim  case Expr::GenericSelectionExprClass:
1058234982Sdim    if (cast<GenericSelectionExpr>(E)->isResultDependent())
1059234982Sdim      return CT_Dependent;
1060234982Sdim    return canThrow(cast<GenericSelectionExpr>(E)->getResultExpr());
1061234982Sdim
1062234982Sdim    // Some expressions are always dependent.
1063234982Sdim  case Expr::CXXDependentScopeMemberExprClass:
1064234982Sdim  case Expr::CXXUnresolvedConstructExprClass:
1065234982Sdim  case Expr::DependentScopeDeclRefExprClass:
1066234982Sdim    return CT_Dependent;
1067234982Sdim
1068234982Sdim  case Expr::AsTypeExprClass:
1069234982Sdim  case Expr::BinaryConditionalOperatorClass:
1070234982Sdim  case Expr::BlockExprClass:
1071234982Sdim  case Expr::CUDAKernelCallExprClass:
1072234982Sdim  case Expr::DeclRefExprClass:
1073234982Sdim  case Expr::ObjCBridgedCastExprClass:
1074234982Sdim  case Expr::ObjCIndirectCopyRestoreExprClass:
1075234982Sdim  case Expr::ObjCProtocolExprClass:
1076234982Sdim  case Expr::ObjCSelectorExprClass:
1077234982Sdim  case Expr::OffsetOfExprClass:
1078234982Sdim  case Expr::PackExpansionExprClass:
1079234982Sdim  case Expr::PseudoObjectExprClass:
1080234982Sdim  case Expr::SubstNonTypeTemplateParmExprClass:
1081234982Sdim  case Expr::SubstNonTypeTemplateParmPackExprClass:
1082243830Sdim  case Expr::FunctionParmPackExprClass:
1083234982Sdim  case Expr::UnaryExprOrTypeTraitExprClass:
1084234982Sdim  case Expr::UnresolvedLookupExprClass:
1085234982Sdim  case Expr::UnresolvedMemberExprClass:
1086234982Sdim    // FIXME: Can any of the above throw?  If so, when?
1087234982Sdim    return CT_Cannot;
1088234982Sdim
1089234982Sdim  case Expr::AddrLabelExprClass:
1090234982Sdim  case Expr::ArrayTypeTraitExprClass:
1091234982Sdim  case Expr::AtomicExprClass:
1092234982Sdim  case Expr::BinaryTypeTraitExprClass:
1093234982Sdim  case Expr::TypeTraitExprClass:
1094234982Sdim  case Expr::CXXBoolLiteralExprClass:
1095234982Sdim  case Expr::CXXNoexceptExprClass:
1096234982Sdim  case Expr::CXXNullPtrLiteralExprClass:
1097234982Sdim  case Expr::CXXPseudoDestructorExprClass:
1098234982Sdim  case Expr::CXXScalarValueInitExprClass:
1099234982Sdim  case Expr::CXXThisExprClass:
1100234982Sdim  case Expr::CXXUuidofExprClass:
1101234982Sdim  case Expr::CharacterLiteralClass:
1102234982Sdim  case Expr::ExpressionTraitExprClass:
1103234982Sdim  case Expr::FloatingLiteralClass:
1104234982Sdim  case Expr::GNUNullExprClass:
1105234982Sdim  case Expr::ImaginaryLiteralClass:
1106234982Sdim  case Expr::ImplicitValueInitExprClass:
1107234982Sdim  case Expr::IntegerLiteralClass:
1108234982Sdim  case Expr::ObjCEncodeExprClass:
1109234982Sdim  case Expr::ObjCStringLiteralClass:
1110234982Sdim  case Expr::ObjCBoolLiteralExprClass:
1111234982Sdim  case Expr::OpaqueValueExprClass:
1112234982Sdim  case Expr::PredefinedExprClass:
1113234982Sdim  case Expr::SizeOfPackExprClass:
1114234982Sdim  case Expr::StringLiteralClass:
1115234982Sdim  case Expr::UnaryTypeTraitExprClass:
1116234982Sdim    // These expressions can never throw.
1117234982Sdim    return CT_Cannot;
1118234982Sdim
1119251662Sdim  case Expr::MSPropertyRefExprClass:
1120251662Sdim    llvm_unreachable("Invalid class for expression");
1121251662Sdim
1122234982Sdim#define STMT(CLASS, PARENT) case Expr::CLASS##Class:
1123234982Sdim#define STMT_RANGE(Base, First, Last)
1124234982Sdim#define LAST_STMT_RANGE(BASE, FIRST, LAST)
1125234982Sdim#define EXPR(CLASS, PARENT)
1126234982Sdim#define ABSTRACT_STMT(STMT)
1127234982Sdim#include "clang/AST/StmtNodes.inc"
1128234982Sdim  case Expr::NoStmtClass:
1129234982Sdim    llvm_unreachable("Invalid class for expression");
1130234982Sdim  }
1131234982Sdim  llvm_unreachable("Bogus StmtClass");
1132234982Sdim}
1133234982Sdim
1134198092Srdivacky} // end namespace clang
1135