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"
15276479Sdim#include "clang/AST/ASTMutationListener.h"
16198092Srdivacky#include "clang/AST/CXXInheritance.h"
17198092Srdivacky#include "clang/AST/Expr.h"
18198092Srdivacky#include "clang/AST/ExprCXX.h"
19206084Srdivacky#include "clang/AST/TypeLoc.h"
20203955Srdivacky#include "clang/Basic/Diagnostic.h"
21203955Srdivacky#include "clang/Basic/SourceManager.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
38280031Sdim/// HACK: libstdc++ has a bug where it shadows std::swap with a member
39280031Sdim/// swap function then tries to call std::swap unqualified from the exception
40280031Sdim/// specification of that function. This function detects whether we're in
41280031Sdim/// such a case and turns off delay-parsing of exception specifications.
42280031Sdimbool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) {
43280031Sdim  auto *RD = dyn_cast<CXXRecordDecl>(CurContext);
44280031Sdim
45280031Sdim  // All the problem cases are member functions named "swap" within class
46280031Sdim  // templates declared directly within namespace std.
47280031Sdim  if (!RD || RD->getEnclosingNamespaceContext() != getStdNamespace() ||
48280031Sdim      !RD->getIdentifier() || !RD->getDescribedClassTemplate() ||
49280031Sdim      !D.getIdentifier() || !D.getIdentifier()->isStr("swap"))
50280031Sdim    return false;
51280031Sdim
52280031Sdim  // Only apply this hack within a system header.
53280031Sdim  if (!Context.getSourceManager().isInSystemHeader(D.getLocStart()))
54280031Sdim    return false;
55280031Sdim
56280031Sdim  return llvm::StringSwitch<bool>(RD->getIdentifier()->getName())
57280031Sdim      .Case("array", true)
58280031Sdim      .Case("pair", true)
59280031Sdim      .Case("priority_queue", true)
60280031Sdim      .Case("stack", true)
61280031Sdim      .Case("queue", true)
62280031Sdim      .Default(false);
63280031Sdim}
64280031Sdim
65198092Srdivacky/// CheckSpecifiedExceptionType - Check if the given type is valid in an
66198092Srdivacky/// exception specification. Incomplete types, or pointers to incomplete types
67198092Srdivacky/// other than void are not allowed.
68249423Sdim///
69249423Sdim/// \param[in,out] T  The exception type. This will be decayed to a pointer type
70249423Sdim///                   when the input is an array or a function type.
71296417Sdimbool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
72249423Sdim  // C++11 [except.spec]p2:
73249423Sdim  //   A type cv T, "array of T", or "function returning T" denoted
74249423Sdim  //   in an exception-specification is adjusted to type T, "pointer to T", or
75249423Sdim  //   "pointer to function returning T", respectively.
76249423Sdim  //
77249423Sdim  // We also apply this rule in C++98.
78249423Sdim  if (T->isArrayType())
79249423Sdim    T = Context.getArrayDecayedType(T);
80249423Sdim  else if (T->isFunctionType())
81249423Sdim    T = Context.getPointerType(T);
82198092Srdivacky
83249423Sdim  int Kind = 0;
84249423Sdim  QualType PointeeT = T;
85249423Sdim  if (const PointerType *PT = T->getAs<PointerType>()) {
86249423Sdim    PointeeT = PT->getPointeeType();
87249423Sdim    Kind = 1;
88198092Srdivacky
89249423Sdim    // cv void* is explicitly permitted, despite being a pointer to an
90249423Sdim    // incomplete type.
91249423Sdim    if (PointeeT->isVoidType())
92249423Sdim      return false;
93249423Sdim  } else if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
94249423Sdim    PointeeT = RT->getPointeeType();
95249423Sdim    Kind = 2;
96198092Srdivacky
97249423Sdim    if (RT->isRValueReferenceType()) {
98249423Sdim      // C++11 [except.spec]p2:
99249423Sdim      //   A type denoted in an exception-specification shall not denote [...]
100249423Sdim      //   an rvalue reference type.
101249423Sdim      Diag(Range.getBegin(), diag::err_rref_in_exception_spec)
102249423Sdim        << T << Range;
103249423Sdim      return true;
104249423Sdim    }
105249423Sdim  }
106249423Sdim
107249423Sdim  // C++11 [except.spec]p2:
108249423Sdim  //   A type denoted in an exception-specification shall not denote an
109249423Sdim  //   incomplete type other than a class currently being defined [...].
110249423Sdim  //   A type denoted in an exception-specification shall not denote a
111249423Sdim  //   pointer or reference to an incomplete type, other than (cv) void* or a
112249423Sdim  //   pointer or reference to a class currently being defined.
113249423Sdim  if (!(PointeeT->isRecordType() &&
114249423Sdim        PointeeT->getAs<RecordType>()->isBeingDefined()) &&
115249423Sdim      RequireCompleteType(Range.getBegin(), PointeeT,
116249423Sdim                          diag::err_incomplete_in_exception_spec, Kind, Range))
117198092Srdivacky    return true;
118198092Srdivacky
119198092Srdivacky  return false;
120198092Srdivacky}
121198092Srdivacky
122198092Srdivacky/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
123198092Srdivacky/// to member to a function with an exception specification. This means that
124198092Srdivacky/// it is invalid to add another level of indirection.
125198092Srdivackybool Sema::CheckDistantExceptionSpec(QualType T) {
126198092Srdivacky  if (const PointerType *PT = T->getAs<PointerType>())
127198092Srdivacky    T = PT->getPointeeType();
128198092Srdivacky  else if (const MemberPointerType *PT = T->getAs<MemberPointerType>())
129198092Srdivacky    T = PT->getPointeeType();
130198092Srdivacky  else
131198092Srdivacky    return false;
132198092Srdivacky
133198092Srdivacky  const FunctionProtoType *FnT = T->getAs<FunctionProtoType>();
134198092Srdivacky  if (!FnT)
135198092Srdivacky    return false;
136198092Srdivacky
137198092Srdivacky  return FnT->hasExceptionSpec();
138198092Srdivacky}
139198092Srdivacky
140234982Sdimconst FunctionProtoType *
141234982SdimSema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
142280031Sdim  if (FPT->getExceptionSpecType() == EST_Unparsed) {
143280031Sdim    Diag(Loc, diag::err_exception_spec_not_parsed);
144280031Sdim    return nullptr;
145280031Sdim  }
146280031Sdim
147239462Sdim  if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
148234982Sdim    return FPT;
149234982Sdim
150234982Sdim  FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl();
151234982Sdim  const FunctionProtoType *SourceFPT =
152234982Sdim      SourceDecl->getType()->castAs<FunctionProtoType>();
153234982Sdim
154239462Sdim  // If the exception specification has already been resolved, just return it.
155239462Sdim  if (!isUnresolvedExceptionSpec(SourceFPT->getExceptionSpecType()))
156234982Sdim    return SourceFPT;
157234982Sdim
158239462Sdim  // Compute or instantiate the exception specification now.
159249423Sdim  if (SourceFPT->getExceptionSpecType() == EST_Unevaluated)
160239462Sdim    EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl));
161239462Sdim  else
162239462Sdim    InstantiateExceptionSpec(Loc, SourceDecl);
163234982Sdim
164288943Sdim  const FunctionProtoType *Proto =
165288943Sdim    SourceDecl->getType()->castAs<FunctionProtoType>();
166288943Sdim  if (Proto->getExceptionSpecType() == clang::EST_Unparsed) {
167288943Sdim    Diag(Loc, diag::err_exception_spec_not_parsed);
168288943Sdim    Proto = nullptr;
169288943Sdim  }
170288943Sdim  return Proto;
171234982Sdim}
172234982Sdim
173280031Sdimvoid
174280031SdimSema::UpdateExceptionSpec(FunctionDecl *FD,
175280031Sdim                          const FunctionProtoType::ExceptionSpecInfo &ESI) {
176276479Sdim  // If we've fully resolved the exception specification, notify listeners.
177280031Sdim  if (!isUnresolvedExceptionSpec(ESI.Type))
178276479Sdim    if (auto *Listener = getASTMutationListener())
179276479Sdim      Listener->ResolvedExceptionSpec(FD);
180288943Sdim
181288943Sdim  for (auto *Redecl : FD->redecls())
182288943Sdim    Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
183276479Sdim}
184276479Sdim
185243830Sdim/// Determine whether a function has an implicitly-generated exception
186243830Sdim/// specification.
187243830Sdimstatic bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
188243830Sdim  if (!isa<CXXDestructorDecl>(Decl) &&
189243830Sdim      Decl->getDeclName().getCXXOverloadedOperator() != OO_Delete &&
190243830Sdim      Decl->getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
191243830Sdim    return false;
192243830Sdim
193276479Sdim  // For a function that the user didn't declare:
194276479Sdim  //  - if this is a destructor, its exception specification is implicit.
195276479Sdim  //  - if this is 'operator delete' or 'operator delete[]', the exception
196276479Sdim  //    specification is as-if an explicit exception specification was given
197276479Sdim  //    (per [basic.stc.dynamic]p2).
198243830Sdim  if (!Decl->getTypeSourceInfo())
199276479Sdim    return isa<CXXDestructorDecl>(Decl);
200243830Sdim
201243830Sdim  const FunctionProtoType *Ty =
202243830Sdim    Decl->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>();
203243830Sdim  return !Ty->hasExceptionSpec();
204243830Sdim}
205243830Sdim
206203955Srdivackybool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
207221345Sdim  OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator();
208221345Sdim  bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;
209206084Srdivacky  bool MissingExceptionSpecification = false;
210203955Srdivacky  bool MissingEmptyExceptionSpecification = false;
211276479Sdim
212221345Sdim  unsigned DiagID = diag::err_mismatched_exception_spec;
213276479Sdim  bool ReturnValueOnError = true;
214276479Sdim  if (getLangOpts().MicrosoftExt) {
215276479Sdim    DiagID = diag::ext_mismatched_exception_spec;
216276479Sdim    ReturnValueOnError = false;
217276479Sdim  }
218234982Sdim
219243830Sdim  // Check the types as written: they must match before any exception
220243830Sdim  // specification adjustment is applied.
221243830Sdim  if (!CheckEquivalentExceptionSpec(
222243830Sdim        PDiag(DiagID), PDiag(diag::note_previous_declaration),
223243830Sdim        Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
224243830Sdim        New->getType()->getAs<FunctionProtoType>(), New->getLocation(),
225243830Sdim        &MissingExceptionSpecification, &MissingEmptyExceptionSpecification,
226243830Sdim        /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) {
227243830Sdim    // C++11 [except.spec]p4 [DR1492]:
228243830Sdim    //   If a declaration of a function has an implicit
229243830Sdim    //   exception-specification, other declarations of the function shall
230243830Sdim    //   not specify an exception-specification.
231249423Sdim    if (getLangOpts().CPlusPlus11 &&
232243830Sdim        hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) {
233243830Sdim      Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch)
234243830Sdim        << hasImplicitExceptionSpec(Old);
235296417Sdim      if (Old->getLocation().isValid())
236243830Sdim        Diag(Old->getLocation(), diag::note_previous_declaration);
237243830Sdim    }
238203955Srdivacky    return false;
239243830Sdim  }
240203955Srdivacky
241261991Sdim  // The failure was something other than an missing exception
242276479Sdim  // specification; return an error, except in MS mode where this is a warning.
243261991Sdim  if (!MissingExceptionSpecification)
244276479Sdim    return ReturnValueOnError;
245203955Srdivacky
246243830Sdim  const FunctionProtoType *NewProto =
247261991Sdim    New->getType()->castAs<FunctionProtoType>();
248218893Sdim
249203955Srdivacky  // The new function declaration is only missing an empty exception
250203955Srdivacky  // specification "throw()". If the throw() specification came from a
251203955Srdivacky  // function in a system header that has C linkage, just add an empty
252203955Srdivacky  // exception specification to the "new" declaration. This is an
253203955Srdivacky  // egregious workaround for glibc, which adds throw() specifications
254203955Srdivacky  // to many libc functions as an optimization. Unfortunately, that
255203955Srdivacky  // optimization isn't permitted by the C++ standard, so we're forced
256203955Srdivacky  // to work around it here.
257218893Sdim  if (MissingEmptyExceptionSpecification && NewProto &&
258206084Srdivacky      (Old->getLocation().isInvalid() ||
259206084Srdivacky       Context.getSourceManager().isInSystemHeader(Old->getLocation())) &&
260203955Srdivacky      Old->isExternC()) {
261280031Sdim    New->setType(Context.getFunctionType(
262280031Sdim        NewProto->getReturnType(), NewProto->getParamTypes(),
263280031Sdim        NewProto->getExtProtoInfo().withExceptionSpec(EST_DynamicNone)));
264203955Srdivacky    return false;
265203955Srdivacky  }
266203955Srdivacky
267261991Sdim  const FunctionProtoType *OldProto =
268261991Sdim    Old->getType()->castAs<FunctionProtoType>();
269206084Srdivacky
270280031Sdim  FunctionProtoType::ExceptionSpecInfo ESI = OldProto->getExceptionSpecType();
271280031Sdim  if (ESI.Type == EST_Dynamic) {
272280031Sdim    ESI.Exceptions = OldProto->exceptions();
273261991Sdim  }
274218893Sdim
275296417Sdim  if (ESI.Type == EST_ComputedNoexcept) {
276296417Sdim    // For computed noexcept, we can't just take the expression from the old
277296417Sdim    // prototype. It likely contains references to the old prototype's
278296417Sdim    // parameters.
279296417Sdim    New->setInvalidDecl();
280296417Sdim  } else {
281296417Sdim    // Update the type of the function with the appropriate exception
282296417Sdim    // specification.
283296417Sdim    New->setType(Context.getFunctionType(
284296417Sdim        NewProto->getReturnType(), NewProto->getParamTypes(),
285296417Sdim        NewProto->getExtProtoInfo().withExceptionSpec(ESI)));
286296417Sdim  }
287206084Srdivacky
288296417Sdim  if (getLangOpts().MicrosoftExt && ESI.Type != EST_ComputedNoexcept) {
289296417Sdim    // Allow missing exception specifications in redeclarations as an extension.
290296417Sdim    DiagID = diag::ext_ms_missing_exception_specification;
291296417Sdim    ReturnValueOnError = false;
292296417Sdim  } else if (New->isReplaceableGlobalAllocationFunction() &&
293296417Sdim             ESI.Type != EST_ComputedNoexcept) {
294296417Sdim    // Allow missing exception specifications in redeclarations as an extension,
295296417Sdim    // when declaring a replaceable global allocation function.
296296417Sdim    DiagID = diag::ext_missing_exception_specification;
297296417Sdim    ReturnValueOnError = false;
298296417Sdim  } else {
299296417Sdim    DiagID = diag::err_missing_exception_specification;
300296417Sdim    ReturnValueOnError = true;
301296417Sdim  }
302296417Sdim
303261991Sdim  // Warn about the lack of exception specification.
304261991Sdim  SmallString<128> ExceptionSpecString;
305261991Sdim  llvm::raw_svector_ostream OS(ExceptionSpecString);
306261991Sdim  switch (OldProto->getExceptionSpecType()) {
307261991Sdim  case EST_DynamicNone:
308261991Sdim    OS << "throw()";
309261991Sdim    break;
310206084Srdivacky
311261991Sdim  case EST_Dynamic: {
312261991Sdim    OS << "throw(";
313261991Sdim    bool OnFirstException = true;
314276479Sdim    for (const auto &E : OldProto->exceptions()) {
315261991Sdim      if (OnFirstException)
316261991Sdim        OnFirstException = false;
317261991Sdim      else
318261991Sdim        OS << ", ";
319261991Sdim
320276479Sdim      OS << E.getAsString(getPrintingPolicy());
321206084Srdivacky    }
322261991Sdim    OS << ")";
323261991Sdim    break;
324261991Sdim  }
325221345Sdim
326261991Sdim  case EST_BasicNoexcept:
327261991Sdim    OS << "noexcept";
328261991Sdim    break;
329221345Sdim
330261991Sdim  case EST_ComputedNoexcept:
331261991Sdim    OS << "noexcept(";
332276479Sdim    assert(OldProto->getNoexceptExpr() != nullptr && "Expected non-null Expr");
333276479Sdim    OldProto->getNoexceptExpr()->printPretty(OS, nullptr, getPrintingPolicy());
334261991Sdim    OS << ")";
335261991Sdim    break;
336221345Sdim
337261991Sdim  default:
338261991Sdim    llvm_unreachable("This spec type is compatible with none.");
339261991Sdim  }
340206084Srdivacky
341261991Sdim  SourceLocation FixItLoc;
342261991Sdim  if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) {
343261991Sdim    TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();
344296417Sdim    // FIXME: Preserve enough information so that we can produce a correct fixit
345296417Sdim    // location when there is a trailing return type.
346296417Sdim    if (auto FTLoc = TL.getAs<FunctionProtoTypeLoc>())
347296417Sdim      if (!FTLoc.getTypePtr()->hasTrailingReturn())
348296417Sdim        FixItLoc = getLocForEndOfToken(FTLoc.getLocalRangeEnd());
349261991Sdim  }
350206084Srdivacky
351261991Sdim  if (FixItLoc.isInvalid())
352296417Sdim    Diag(New->getLocation(), DiagID)
353261991Sdim      << New << OS.str();
354261991Sdim  else {
355296417Sdim    Diag(New->getLocation(), DiagID)
356261991Sdim      << New << OS.str()
357261991Sdim      << FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str());
358261991Sdim  }
359206084Srdivacky
360296417Sdim  if (Old->getLocation().isValid())
361261991Sdim    Diag(Old->getLocation(), diag::note_previous_declaration);
362206084Srdivacky
363296417Sdim  return ReturnValueOnError;
364203955Srdivacky}
365203955Srdivacky
366198092Srdivacky/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
367198092Srdivacky/// exception specifications. Exception specifications are equivalent if
368198092Srdivacky/// they allow exactly the same set of exception types. It does not matter how
369198092Srdivacky/// that is achieved. See C++ [except.spec]p2.
370198092Srdivackybool Sema::CheckEquivalentExceptionSpec(
371198092Srdivacky    const FunctionProtoType *Old, SourceLocation OldLoc,
372198092Srdivacky    const FunctionProtoType *New, SourceLocation NewLoc) {
373221345Sdim  unsigned DiagID = diag::err_mismatched_exception_spec;
374234353Sdim  if (getLangOpts().MicrosoftExt)
375276479Sdim    DiagID = diag::ext_mismatched_exception_spec;
376276479Sdim  bool Result = CheckEquivalentExceptionSpec(PDiag(DiagID),
377276479Sdim      PDiag(diag::note_previous_declaration), Old, OldLoc, New, NewLoc);
378276479Sdim
379276479Sdim  // In Microsoft mode, mismatching exception specifications just cause a warning.
380276479Sdim  if (getLangOpts().MicrosoftExt)
381276479Sdim    return false;
382276479Sdim  return Result;
383198092Srdivacky}
384198092Srdivacky
385221345Sdim/// CheckEquivalentExceptionSpec - Check if the two types have compatible
386221345Sdim/// exception specifications. See C++ [except.spec]p3.
387243830Sdim///
388243830Sdim/// \return \c false if the exception specifications match, \c true if there is
389243830Sdim/// a problem. If \c true is returned, either a diagnostic has already been
390243830Sdim/// produced or \c *MissingExceptionSpecification is set to \c true.
391221345Sdimbool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
392206084Srdivacky                                        const PartialDiagnostic & NoteID,
393221345Sdim                                        const FunctionProtoType *Old,
394206084Srdivacky                                        SourceLocation OldLoc,
395221345Sdim                                        const FunctionProtoType *New,
396206084Srdivacky                                        SourceLocation NewLoc,
397206084Srdivacky                                        bool *MissingExceptionSpecification,
398221345Sdim                                        bool*MissingEmptyExceptionSpecification,
399221345Sdim                                        bool AllowNoexceptAllMatchWithNoSpec,
400221345Sdim                                        bool IsOperatorNew) {
401210299Sed  // Just completely ignore this under -fno-exceptions.
402234353Sdim  if (!getLangOpts().CXXExceptions)
403210299Sed    return false;
404210299Sed
405206084Srdivacky  if (MissingExceptionSpecification)
406206084Srdivacky    *MissingExceptionSpecification = false;
407206084Srdivacky
408203955Srdivacky  if (MissingEmptyExceptionSpecification)
409203955Srdivacky    *MissingEmptyExceptionSpecification = false;
410203955Srdivacky
411234982Sdim  Old = ResolveExceptionSpec(NewLoc, Old);
412234982Sdim  if (!Old)
413234982Sdim    return false;
414234982Sdim  New = ResolveExceptionSpec(NewLoc, New);
415234982Sdim  if (!New)
416234982Sdim    return false;
417234982Sdim
418221345Sdim  // C++0x [except.spec]p3: Two exception-specifications are compatible if:
419221345Sdim  //   - both are non-throwing, regardless of their form,
420221345Sdim  //   - both have the form noexcept(constant-expression) and the constant-
421221345Sdim  //     expressions are equivalent,
422221345Sdim  //   - both are dynamic-exception-specifications that have the same set of
423221345Sdim  //     adjusted types.
424221345Sdim  //
425288943Sdim  // C++0x [except.spec]p12: An exception-specification is non-throwing if it is
426221345Sdim  //   of the form throw(), noexcept, or noexcept(constant-expression) where the
427221345Sdim  //   constant-expression yields true.
428221345Sdim  //
429221345Sdim  // C++0x [except.spec]p4: If any declaration of a function has an exception-
430221345Sdim  //   specifier that is not a noexcept-specification allowing all exceptions,
431221345Sdim  //   all declarations [...] of that function shall have a compatible
432221345Sdim  //   exception-specification.
433221345Sdim  //
434221345Sdim  // That last point basically means that noexcept(false) matches no spec.
435221345Sdim  // It's considered when AllowNoexceptAllMatchWithNoSpec is true.
436221345Sdim
437221345Sdim  ExceptionSpecificationType OldEST = Old->getExceptionSpecType();
438221345Sdim  ExceptionSpecificationType NewEST = New->getExceptionSpecType();
439221345Sdim
440239462Sdim  assert(!isUnresolvedExceptionSpec(OldEST) &&
441239462Sdim         !isUnresolvedExceptionSpec(NewEST) &&
442223017Sdim         "Shouldn't see unknown exception specifications here");
443223017Sdim
444221345Sdim  // Shortcut the case where both have no spec.
445221345Sdim  if (OldEST == EST_None && NewEST == EST_None)
446221345Sdim    return false;
447221345Sdim
448221345Sdim  FunctionProtoType::NoexceptResult OldNR = Old->getNoexceptSpec(Context);
449221345Sdim  FunctionProtoType::NoexceptResult NewNR = New->getNoexceptSpec(Context);
450221345Sdim  if (OldNR == FunctionProtoType::NR_BadNoexcept ||
451221345Sdim      NewNR == FunctionProtoType::NR_BadNoexcept)
452221345Sdim    return false;
453221345Sdim
454221345Sdim  // Dependent noexcept specifiers are compatible with each other, but nothing
455221345Sdim  // else.
456221345Sdim  // One noexcept is compatible with another if the argument is the same
457221345Sdim  if (OldNR == NewNR &&
458221345Sdim      OldNR != FunctionProtoType::NR_NoNoexcept &&
459221345Sdim      NewNR != FunctionProtoType::NR_NoNoexcept)
460221345Sdim    return false;
461221345Sdim  if (OldNR != NewNR &&
462221345Sdim      OldNR != FunctionProtoType::NR_NoNoexcept &&
463221345Sdim      NewNR != FunctionProtoType::NR_NoNoexcept) {
464221345Sdim    Diag(NewLoc, DiagID);
465288943Sdim    if (NoteID.getDiagID() != 0 && OldLoc.isValid())
466221345Sdim      Diag(OldLoc, NoteID);
467221345Sdim    return true;
468212904Sdim  }
469212904Sdim
470221345Sdim  // The MS extension throw(...) is compatible with itself.
471221345Sdim  if (OldEST == EST_MSAny && NewEST == EST_MSAny)
472198092Srdivacky    return false;
473221345Sdim
474221345Sdim  // It's also compatible with no spec.
475221345Sdim  if ((OldEST == EST_None && NewEST == EST_MSAny) ||
476221345Sdim      (OldEST == EST_MSAny && NewEST == EST_None))
477221345Sdim    return false;
478221345Sdim
479221345Sdim  // It's also compatible with noexcept(false).
480221345Sdim  if (OldEST == EST_MSAny && NewNR == FunctionProtoType::NR_Throw)
481221345Sdim    return false;
482221345Sdim  if (NewEST == EST_MSAny && OldNR == FunctionProtoType::NR_Throw)
483221345Sdim    return false;
484221345Sdim
485221345Sdim  // As described above, noexcept(false) matches no spec only for functions.
486221345Sdim  if (AllowNoexceptAllMatchWithNoSpec) {
487221345Sdim    if (OldEST == EST_None && NewNR == FunctionProtoType::NR_Throw)
488221345Sdim      return false;
489221345Sdim    if (NewEST == EST_None && OldNR == FunctionProtoType::NR_Throw)
490221345Sdim      return false;
491221345Sdim  }
492221345Sdim
493221345Sdim  // Any non-throwing specifications are compatible.
494221345Sdim  bool OldNonThrowing = OldNR == FunctionProtoType::NR_Nothrow ||
495221345Sdim                        OldEST == EST_DynamicNone;
496221345Sdim  bool NewNonThrowing = NewNR == FunctionProtoType::NR_Nothrow ||
497221345Sdim                        NewEST == EST_DynamicNone;
498221345Sdim  if (OldNonThrowing && NewNonThrowing)
499221345Sdim    return false;
500221345Sdim
501221345Sdim  // As a special compatibility feature, under C++0x we accept no spec and
502221345Sdim  // throw(std::bad_alloc) as equivalent for operator new and operator new[].
503221345Sdim  // This is because the implicit declaration changed, but old code would break.
504249423Sdim  if (getLangOpts().CPlusPlus11 && IsOperatorNew) {
505276479Sdim    const FunctionProtoType *WithExceptions = nullptr;
506221345Sdim    if (OldEST == EST_None && NewEST == EST_Dynamic)
507221345Sdim      WithExceptions = New;
508221345Sdim    else if (OldEST == EST_Dynamic && NewEST == EST_None)
509221345Sdim      WithExceptions = Old;
510221345Sdim    if (WithExceptions && WithExceptions->getNumExceptions() == 1) {
511221345Sdim      // One has no spec, the other throw(something). If that something is
512221345Sdim      // std::bad_alloc, all conditions are met.
513221345Sdim      QualType Exception = *WithExceptions->exception_begin();
514221345Sdim      if (CXXRecordDecl *ExRecord = Exception->getAsCXXRecordDecl()) {
515221345Sdim        IdentifierInfo* Name = ExRecord->getIdentifier();
516221345Sdim        if (Name && Name->getName() == "bad_alloc") {
517221345Sdim          // It's called bad_alloc, but is it in std?
518276479Sdim          if (ExRecord->isInStdNamespace()) {
519276479Sdim            return false;
520221345Sdim          }
521221345Sdim        }
522221345Sdim      }
523221345Sdim    }
524221345Sdim  }
525221345Sdim
526221345Sdim  // At this point, the only remaining valid case is two matching dynamic
527221345Sdim  // specifications. We return here unless both specifications are dynamic.
528221345Sdim  if (OldEST != EST_Dynamic || NewEST != EST_Dynamic) {
529206084Srdivacky    if (MissingExceptionSpecification && Old->hasExceptionSpec() &&
530203955Srdivacky        !New->hasExceptionSpec()) {
531206084Srdivacky      // The old type has an exception specification of some sort, but
532206084Srdivacky      // the new type does not.
533206084Srdivacky      *MissingExceptionSpecification = true;
534206084Srdivacky
535221345Sdim      if (MissingEmptyExceptionSpecification && OldNonThrowing) {
536221345Sdim        // The old type has a throw() or noexcept(true) exception specification
537221345Sdim        // and the new type has no exception specification, and the caller asked
538206084Srdivacky        // to handle this itself.
539206084Srdivacky        *MissingEmptyExceptionSpecification = true;
540206084Srdivacky      }
541206084Srdivacky
542203955Srdivacky      return true;
543203955Srdivacky    }
544203955Srdivacky
545198092Srdivacky    Diag(NewLoc, DiagID);
546288943Sdim    if (NoteID.getDiagID() != 0 && OldLoc.isValid())
547198092Srdivacky      Diag(OldLoc, NoteID);
548198092Srdivacky    return true;
549198092Srdivacky  }
550198092Srdivacky
551221345Sdim  assert(OldEST == EST_Dynamic && NewEST == EST_Dynamic &&
552221345Sdim      "Exception compatibility logic error: non-dynamic spec slipped through.");
553221345Sdim
554198092Srdivacky  bool Success = true;
555221345Sdim  // Both have a dynamic exception spec. Collect the first set, then compare
556198092Srdivacky  // to the second.
557198092Srdivacky  llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes;
558276479Sdim  for (const auto &I : Old->exceptions())
559276479Sdim    OldTypes.insert(Context.getCanonicalType(I).getUnqualifiedType());
560198092Srdivacky
561276479Sdim  for (const auto &I : New->exceptions()) {
562276479Sdim    CanQualType TypePtr = Context.getCanonicalType(I).getUnqualifiedType();
563198092Srdivacky    if(OldTypes.count(TypePtr))
564198092Srdivacky      NewTypes.insert(TypePtr);
565198092Srdivacky    else
566198092Srdivacky      Success = false;
567198092Srdivacky  }
568198092Srdivacky
569198092Srdivacky  Success = Success && OldTypes.size() == NewTypes.size();
570198092Srdivacky
571198092Srdivacky  if (Success) {
572198092Srdivacky    return false;
573198092Srdivacky  }
574198092Srdivacky  Diag(NewLoc, DiagID);
575288943Sdim  if (NoteID.getDiagID() != 0 && OldLoc.isValid())
576198092Srdivacky    Diag(OldLoc, NoteID);
577198092Srdivacky  return true;
578198092Srdivacky}
579198092Srdivacky
580198092Srdivacky/// CheckExceptionSpecSubset - Check whether the second function type's
581198092Srdivacky/// exception specification is a subset (or equivalent) of the first function
582198092Srdivacky/// type. This is used by override and pointer assignment checks.
583198092Srdivackybool Sema::CheckExceptionSpecSubset(
584198092Srdivacky    const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
585198092Srdivacky    const FunctionProtoType *Superset, SourceLocation SuperLoc,
586198092Srdivacky    const FunctionProtoType *Subset, SourceLocation SubLoc) {
587210299Sed
588210299Sed  // Just auto-succeed under -fno-exceptions.
589234353Sdim  if (!getLangOpts().CXXExceptions)
590210299Sed    return false;
591210299Sed
592198092Srdivacky  // FIXME: As usual, we could be more specific in our error messages, but
593198092Srdivacky  // that better waits until we've got types with source locations.
594198092Srdivacky
595198092Srdivacky  if (!SubLoc.isValid())
596198092Srdivacky    SubLoc = SuperLoc;
597198092Srdivacky
598234982Sdim  // Resolve the exception specifications, if needed.
599234982Sdim  Superset = ResolveExceptionSpec(SuperLoc, Superset);
600234982Sdim  if (!Superset)
601234982Sdim    return false;
602234982Sdim  Subset = ResolveExceptionSpec(SubLoc, Subset);
603234982Sdim  if (!Subset)
604234982Sdim    return false;
605234982Sdim
606221345Sdim  ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType();
607221345Sdim
608198092Srdivacky  // If superset contains everything, we're done.
609221345Sdim  if (SuperEST == EST_None || SuperEST == EST_MSAny)
610198092Srdivacky    return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
611198092Srdivacky
612221345Sdim  // If there are dependent noexcept specs, assume everything is fine. Unlike
613221345Sdim  // with the equivalency check, this is safe in this case, because we don't
614221345Sdim  // want to merge declarations. Checks after instantiation will catch any
615221345Sdim  // omissions we make here.
616221345Sdim  // We also shortcut checking if a noexcept expression was bad.
617221345Sdim
618221345Sdim  FunctionProtoType::NoexceptResult SuperNR =Superset->getNoexceptSpec(Context);
619221345Sdim  if (SuperNR == FunctionProtoType::NR_BadNoexcept ||
620221345Sdim      SuperNR == FunctionProtoType::NR_Dependent)
621221345Sdim    return false;
622221345Sdim
623221345Sdim  // Another case of the superset containing everything.
624221345Sdim  if (SuperNR == FunctionProtoType::NR_Throw)
625221345Sdim    return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
626221345Sdim
627221345Sdim  ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
628221345Sdim
629239462Sdim  assert(!isUnresolvedExceptionSpec(SuperEST) &&
630239462Sdim         !isUnresolvedExceptionSpec(SubEST) &&
631223017Sdim         "Shouldn't see unknown exception specifications here");
632223017Sdim
633198092Srdivacky  // It does not. If the subset contains everything, we've failed.
634221345Sdim  if (SubEST == EST_None || SubEST == EST_MSAny) {
635198092Srdivacky    Diag(SubLoc, DiagID);
636198092Srdivacky    if (NoteID.getDiagID() != 0)
637198092Srdivacky      Diag(SuperLoc, NoteID);
638198092Srdivacky    return true;
639198092Srdivacky  }
640198092Srdivacky
641221345Sdim  FunctionProtoType::NoexceptResult SubNR = Subset->getNoexceptSpec(Context);
642221345Sdim  if (SubNR == FunctionProtoType::NR_BadNoexcept ||
643221345Sdim      SubNR == FunctionProtoType::NR_Dependent)
644221345Sdim    return false;
645221345Sdim
646221345Sdim  // Another case of the subset containing everything.
647221345Sdim  if (SubNR == FunctionProtoType::NR_Throw) {
648221345Sdim    Diag(SubLoc, DiagID);
649221345Sdim    if (NoteID.getDiagID() != 0)
650221345Sdim      Diag(SuperLoc, NoteID);
651221345Sdim    return true;
652221345Sdim  }
653221345Sdim
654221345Sdim  // If the subset contains nothing, we're done.
655221345Sdim  if (SubEST == EST_DynamicNone || SubNR == FunctionProtoType::NR_Nothrow)
656221345Sdim    return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
657221345Sdim
658221345Sdim  // Otherwise, if the superset contains nothing, we've failed.
659221345Sdim  if (SuperEST == EST_DynamicNone || SuperNR == FunctionProtoType::NR_Nothrow) {
660221345Sdim    Diag(SubLoc, DiagID);
661221345Sdim    if (NoteID.getDiagID() != 0)
662221345Sdim      Diag(SuperLoc, NoteID);
663221345Sdim    return true;
664221345Sdim  }
665221345Sdim
666221345Sdim  assert(SuperEST == EST_Dynamic && SubEST == EST_Dynamic &&
667221345Sdim         "Exception spec subset: non-dynamic case slipped through.");
668221345Sdim
669221345Sdim  // Neither contains everything or nothing. Do a proper comparison.
670276479Sdim  for (const auto &SubI : Subset->exceptions()) {
671198092Srdivacky    // Take one type from the subset.
672276479Sdim    QualType CanonicalSubT = Context.getCanonicalType(SubI);
673198092Srdivacky    // Unwrap pointers and references so that we can do checks within a class
674198092Srdivacky    // hierarchy. Don't unwrap member pointers; they don't have hierarchy
675198092Srdivacky    // conversions on the pointee.
676198092Srdivacky    bool SubIsPointer = false;
677198092Srdivacky    if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>())
678198092Srdivacky      CanonicalSubT = RefTy->getPointeeType();
679198092Srdivacky    if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) {
680198092Srdivacky      CanonicalSubT = PtrTy->getPointeeType();
681198092Srdivacky      SubIsPointer = true;
682198092Srdivacky    }
683198092Srdivacky    bool SubIsClass = CanonicalSubT->isRecordType();
684199482Srdivacky    CanonicalSubT = CanonicalSubT.getLocalUnqualifiedType();
685198092Srdivacky
686198092Srdivacky    CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
687198092Srdivacky                       /*DetectVirtual=*/false);
688198092Srdivacky
689198092Srdivacky    bool Contained = false;
690198092Srdivacky    // Make sure it's in the superset.
691276479Sdim    for (const auto &SuperI : Superset->exceptions()) {
692276479Sdim      QualType CanonicalSuperT = Context.getCanonicalType(SuperI);
693198092Srdivacky      // SubT must be SuperT or derived from it, or pointer or reference to
694198092Srdivacky      // such types.
695198092Srdivacky      if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>())
696198092Srdivacky        CanonicalSuperT = RefTy->getPointeeType();
697198092Srdivacky      if (SubIsPointer) {
698198092Srdivacky        if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>())
699198092Srdivacky          CanonicalSuperT = PtrTy->getPointeeType();
700198092Srdivacky        else {
701198092Srdivacky          continue;
702198092Srdivacky        }
703198092Srdivacky      }
704199482Srdivacky      CanonicalSuperT = CanonicalSuperT.getLocalUnqualifiedType();
705198092Srdivacky      // If the types are the same, move on to the next type in the subset.
706198092Srdivacky      if (CanonicalSubT == CanonicalSuperT) {
707198092Srdivacky        Contained = true;
708198092Srdivacky        break;
709198092Srdivacky      }
710198092Srdivacky
711198092Srdivacky      // Otherwise we need to check the inheritance.
712198092Srdivacky      if (!SubIsClass || !CanonicalSuperT->isRecordType())
713198092Srdivacky        continue;
714198092Srdivacky
715198092Srdivacky      Paths.clear();
716296417Sdim      if (!IsDerivedFrom(SubLoc, CanonicalSubT, CanonicalSuperT, Paths))
717198092Srdivacky        continue;
718198092Srdivacky
719208600Srdivacky      if (Paths.isAmbiguous(Context.getCanonicalType(CanonicalSuperT)))
720198092Srdivacky        continue;
721198092Srdivacky
722203955Srdivacky      // Do this check from a context without privileges.
723205219Srdivacky      switch (CheckBaseClassAccess(SourceLocation(),
724203955Srdivacky                                   CanonicalSuperT, CanonicalSubT,
725203955Srdivacky                                   Paths.front(),
726205219Srdivacky                                   /*Diagnostic*/ 0,
727203955Srdivacky                                   /*ForceCheck*/ true,
728205219Srdivacky                                   /*ForceUnprivileged*/ true)) {
729203955Srdivacky      case AR_accessible: break;
730203955Srdivacky      case AR_inaccessible: continue;
731203955Srdivacky      case AR_dependent:
732203955Srdivacky        llvm_unreachable("access check dependent for unprivileged context");
733203955Srdivacky      case AR_delayed:
734203955Srdivacky        llvm_unreachable("access check delayed in non-declaration");
735203955Srdivacky      }
736198092Srdivacky
737198092Srdivacky      Contained = true;
738198092Srdivacky      break;
739198092Srdivacky    }
740198092Srdivacky    if (!Contained) {
741198092Srdivacky      Diag(SubLoc, DiagID);
742198092Srdivacky      if (NoteID.getDiagID() != 0)
743198092Srdivacky        Diag(SuperLoc, NoteID);
744198092Srdivacky      return true;
745198092Srdivacky    }
746198092Srdivacky  }
747198092Srdivacky  // We've run half the gauntlet.
748198092Srdivacky  return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
749198092Srdivacky}
750198092Srdivacky
751198092Srdivackystatic bool CheckSpecForTypesEquivalent(Sema &S,
752198092Srdivacky    const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
753198092Srdivacky    QualType Target, SourceLocation TargetLoc,
754198092Srdivacky    QualType Source, SourceLocation SourceLoc)
755198092Srdivacky{
756198092Srdivacky  const FunctionProtoType *TFunc = GetUnderlyingFunction(Target);
757198092Srdivacky  if (!TFunc)
758198092Srdivacky    return false;
759198092Srdivacky  const FunctionProtoType *SFunc = GetUnderlyingFunction(Source);
760198092Srdivacky  if (!SFunc)
761198092Srdivacky    return false;
762198092Srdivacky
763198092Srdivacky  return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc,
764198092Srdivacky                                        SFunc, SourceLoc);
765198092Srdivacky}
766198092Srdivacky
767198092Srdivacky/// CheckParamExceptionSpec - Check if the parameter and return types of the
768198092Srdivacky/// two functions have equivalent exception specs. This is part of the
769198092Srdivacky/// assignment and override compatibility check. We do not check the parameters
770198092Srdivacky/// of parameter function pointers recursively, as no sane programmer would
771198092Srdivacky/// even be able to write such a function type.
772280031Sdimbool Sema::CheckParamExceptionSpec(const PartialDiagnostic &NoteID,
773280031Sdim                                   const FunctionProtoType *Target,
774280031Sdim                                   SourceLocation TargetLoc,
775280031Sdim                                   const FunctionProtoType *Source,
776280031Sdim                                   SourceLocation SourceLoc) {
777276479Sdim  if (CheckSpecForTypesEquivalent(
778276479Sdim          *this, PDiag(diag::err_deep_exception_specs_differ) << 0, PDiag(),
779276479Sdim          Target->getReturnType(), TargetLoc, Source->getReturnType(),
780276479Sdim          SourceLoc))
781198092Srdivacky    return true;
782198092Srdivacky
783198092Srdivacky  // We shouldn't even be testing this unless the arguments are otherwise
784198092Srdivacky  // compatible.
785276479Sdim  assert(Target->getNumParams() == Source->getNumParams() &&
786198092Srdivacky         "Functions have different argument counts.");
787276479Sdim  for (unsigned i = 0, E = Target->getNumParams(); i != E; ++i) {
788276479Sdim    if (CheckSpecForTypesEquivalent(
789276479Sdim            *this, PDiag(diag::err_deep_exception_specs_differ) << 1, PDiag(),
790276479Sdim            Target->getParamType(i), TargetLoc, Source->getParamType(i),
791276479Sdim            SourceLoc))
792198092Srdivacky      return true;
793198092Srdivacky  }
794198092Srdivacky  return false;
795198092Srdivacky}
796198092Srdivacky
797280031Sdimbool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) {
798198092Srdivacky  // First we check for applicability.
799198092Srdivacky  // Target type must be a function, function pointer or function reference.
800198092Srdivacky  const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType);
801280031Sdim  if (!ToFunc || ToFunc->hasDependentExceptionSpec())
802198092Srdivacky    return false;
803198092Srdivacky
804198092Srdivacky  // SourceType must be a function or function pointer.
805198092Srdivacky  const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType());
806280031Sdim  if (!FromFunc || FromFunc->hasDependentExceptionSpec())
807198092Srdivacky    return false;
808198092Srdivacky
809198092Srdivacky  // Now we've got the correct types on both sides, check their compatibility.
810198092Srdivacky  // This means that the source of the conversion can only throw a subset of
811198092Srdivacky  // the exceptions of the target, and any exception specs on arguments or
812198092Srdivacky  // return types must be equivalent.
813280031Sdim  //
814280031Sdim  // FIXME: If there is a nested dependent exception specification, we should
815280031Sdim  // not be checking it here. This is fine:
816280031Sdim  //   template<typename T> void f() {
817280031Sdim  //     void (*p)(void (*) throw(T));
818280031Sdim  //     void (*q)(void (*) throw(int)) = p;
819280031Sdim  //   }
820280031Sdim  // ... because it might be instantiated with T=int.
821206084Srdivacky  return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs),
822206084Srdivacky                                  PDiag(), ToFunc,
823206084Srdivacky                                  From->getSourceRange().getBegin(),
824198092Srdivacky                                  FromFunc, SourceLocation());
825198092Srdivacky}
826198092Srdivacky
827198092Srdivackybool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
828198092Srdivacky                                                const CXXMethodDecl *Old) {
829280031Sdim  // If the new exception specification hasn't been parsed yet, skip the check.
830280031Sdim  // We'll get called again once it's been parsed.
831280031Sdim  if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==
832280031Sdim      EST_Unparsed)
833280031Sdim    return false;
834249423Sdim  if (getLangOpts().CPlusPlus11 && isa<CXXDestructorDecl>(New)) {
835223017Sdim    // Don't check uninstantiated template destructors at all. We can only
836223017Sdim    // synthesize correct specs after the template is instantiated.
837223017Sdim    if (New->getParent()->isDependentType())
838223017Sdim      return false;
839223017Sdim    if (New->getParent()->isBeingDefined()) {
840223017Sdim      // The destructor might be updated once the definition is finished. So
841223017Sdim      // remember it and check later.
842280031Sdim      DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old));
843223017Sdim      return false;
844223017Sdim    }
845223017Sdim  }
846280031Sdim  // If the old exception specification hasn't been parsed yet, remember that
847280031Sdim  // we need to perform this check when we get to the end of the outermost
848280031Sdim  // lexically-surrounding class.
849280031Sdim  if (Old->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==
850280031Sdim      EST_Unparsed) {
851280031Sdim    DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old));
852280031Sdim    return false;
853280031Sdim  }
854223017Sdim  unsigned DiagID = diag::err_override_exception_spec;
855234353Sdim  if (getLangOpts().MicrosoftExt)
856276479Sdim    DiagID = diag::ext_override_exception_spec;
857223017Sdim  return CheckExceptionSpecSubset(PDiag(DiagID),
858206084Srdivacky                                  PDiag(diag::note_overridden_virtual_function),
859198092Srdivacky                                  Old->getType()->getAs<FunctionProtoType>(),
860198092Srdivacky                                  Old->getLocation(),
861198092Srdivacky                                  New->getType()->getAs<FunctionProtoType>(),
862198092Srdivacky                                  New->getLocation());
863198092Srdivacky}
864198092Srdivacky
865288943Sdimstatic CanThrowResult canSubExprsThrow(Sema &S, const Expr *E) {
866234982Sdim  CanThrowResult R = CT_Cannot;
867288943Sdim  for (const Stmt *SubStmt : E->children()) {
868288943Sdim    R = mergeCanThrow(R, S.canThrow(cast<Expr>(SubStmt)));
869288943Sdim    if (R == CT_Can)
870288943Sdim      break;
871288943Sdim  }
872234982Sdim  return R;
873234982Sdim}
874234982Sdim
875261991Sdimstatic CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) {
876261991Sdim  assert(D && "Expected decl");
877234982Sdim
878234982Sdim  // See if we can get a function type from the decl somehow.
879234982Sdim  const ValueDecl *VD = dyn_cast<ValueDecl>(D);
880234982Sdim  if (!VD) // If we have no clue what we're calling, assume the worst.
881234982Sdim    return CT_Can;
882234982Sdim
883234982Sdim  // As an extension, we assume that __attribute__((nothrow)) functions don't
884234982Sdim  // throw.
885234982Sdim  if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
886234982Sdim    return CT_Cannot;
887234982Sdim
888234982Sdim  QualType T = VD->getType();
889234982Sdim  const FunctionProtoType *FT;
890234982Sdim  if ((FT = T->getAs<FunctionProtoType>())) {
891234982Sdim  } else if (const PointerType *PT = T->getAs<PointerType>())
892234982Sdim    FT = PT->getPointeeType()->getAs<FunctionProtoType>();
893234982Sdim  else if (const ReferenceType *RT = T->getAs<ReferenceType>())
894234982Sdim    FT = RT->getPointeeType()->getAs<FunctionProtoType>();
895234982Sdim  else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())
896234982Sdim    FT = MT->getPointeeType()->getAs<FunctionProtoType>();
897234982Sdim  else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())
898234982Sdim    FT = BT->getPointeeType()->getAs<FunctionProtoType>();
899234982Sdim
900234982Sdim  if (!FT)
901234982Sdim    return CT_Can;
902234982Sdim
903234982Sdim  FT = S.ResolveExceptionSpec(E->getLocStart(), FT);
904234982Sdim  if (!FT)
905234982Sdim    return CT_Can;
906234982Sdim
907234982Sdim  return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can;
908234982Sdim}
909234982Sdim
910234982Sdimstatic CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) {
911234982Sdim  if (DC->isTypeDependent())
912234982Sdim    return CT_Dependent;
913234982Sdim
914234982Sdim  if (!DC->getTypeAsWritten()->isReferenceType())
915234982Sdim    return CT_Cannot;
916234982Sdim
917234982Sdim  if (DC->getSubExpr()->isTypeDependent())
918234982Sdim    return CT_Dependent;
919234982Sdim
920234982Sdim  return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot;
921234982Sdim}
922234982Sdim
923234982Sdimstatic CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) {
924234982Sdim  if (DC->isTypeOperand())
925234982Sdim    return CT_Cannot;
926234982Sdim
927234982Sdim  Expr *Op = DC->getExprOperand();
928234982Sdim  if (Op->isTypeDependent())
929234982Sdim    return CT_Dependent;
930234982Sdim
931234982Sdim  const RecordType *RT = Op->getType()->getAs<RecordType>();
932234982Sdim  if (!RT)
933234982Sdim    return CT_Cannot;
934234982Sdim
935234982Sdim  if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())
936234982Sdim    return CT_Cannot;
937234982Sdim
938234982Sdim  if (Op->Classify(S.Context).isPRValue())
939234982Sdim    return CT_Cannot;
940234982Sdim
941234982Sdim  return CT_Can;
942234982Sdim}
943234982Sdim
944234982SdimCanThrowResult Sema::canThrow(const Expr *E) {
945234982Sdim  // C++ [expr.unary.noexcept]p3:
946234982Sdim  //   [Can throw] if in a potentially-evaluated context the expression would
947234982Sdim  //   contain:
948234982Sdim  switch (E->getStmtClass()) {
949234982Sdim  case Expr::CXXThrowExprClass:
950234982Sdim    //   - a potentially evaluated throw-expression
951234982Sdim    return CT_Can;
952234982Sdim
953234982Sdim  case Expr::CXXDynamicCastExprClass: {
954234982Sdim    //   - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),
955234982Sdim    //     where T is a reference type, that requires a run-time check
956234982Sdim    CanThrowResult CT = canDynamicCastThrow(cast<CXXDynamicCastExpr>(E));
957234982Sdim    if (CT == CT_Can)
958234982Sdim      return CT;
959234982Sdim    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
960234982Sdim  }
961234982Sdim
962234982Sdim  case Expr::CXXTypeidExprClass:
963234982Sdim    //   - a potentially evaluated typeid expression applied to a glvalue
964234982Sdim    //     expression whose type is a polymorphic class type
965234982Sdim    return canTypeidThrow(*this, cast<CXXTypeidExpr>(E));
966234982Sdim
967234982Sdim    //   - a potentially evaluated call to a function, member function, function
968234982Sdim    //     pointer, or member function pointer that does not have a non-throwing
969234982Sdim    //     exception-specification
970234982Sdim  case Expr::CallExprClass:
971234982Sdim  case Expr::CXXMemberCallExprClass:
972234982Sdim  case Expr::CXXOperatorCallExprClass:
973234982Sdim  case Expr::UserDefinedLiteralClass: {
974234982Sdim    const CallExpr *CE = cast<CallExpr>(E);
975234982Sdim    CanThrowResult CT;
976234982Sdim    if (E->isTypeDependent())
977234982Sdim      CT = CT_Dependent;
978234982Sdim    else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
979234982Sdim      CT = CT_Cannot;
980261991Sdim    else if (CE->getCalleeDecl())
981261991Sdim      CT = canCalleeThrow(*this, E, CE->getCalleeDecl());
982234982Sdim    else
983261991Sdim      CT = CT_Can;
984234982Sdim    if (CT == CT_Can)
985234982Sdim      return CT;
986234982Sdim    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
987234982Sdim  }
988234982Sdim
989234982Sdim  case Expr::CXXConstructExprClass:
990234982Sdim  case Expr::CXXTemporaryObjectExprClass: {
991234982Sdim    CanThrowResult CT = canCalleeThrow(*this, E,
992234982Sdim        cast<CXXConstructExpr>(E)->getConstructor());
993234982Sdim    if (CT == CT_Can)
994234982Sdim      return CT;
995234982Sdim    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
996234982Sdim  }
997234982Sdim
998234982Sdim  case Expr::LambdaExprClass: {
999234982Sdim    const LambdaExpr *Lambda = cast<LambdaExpr>(E);
1000234982Sdim    CanThrowResult CT = CT_Cannot;
1001296417Sdim    for (LambdaExpr::const_capture_init_iterator
1002296417Sdim             Cap = Lambda->capture_init_begin(),
1003296417Sdim             CapEnd = Lambda->capture_init_end();
1004234982Sdim         Cap != CapEnd; ++Cap)
1005234982Sdim      CT = mergeCanThrow(CT, canThrow(*Cap));
1006234982Sdim    return CT;
1007234982Sdim  }
1008234982Sdim
1009234982Sdim  case Expr::CXXNewExprClass: {
1010234982Sdim    CanThrowResult CT;
1011234982Sdim    if (E->isTypeDependent())
1012234982Sdim      CT = CT_Dependent;
1013234982Sdim    else
1014234982Sdim      CT = canCalleeThrow(*this, E, cast<CXXNewExpr>(E)->getOperatorNew());
1015234982Sdim    if (CT == CT_Can)
1016234982Sdim      return CT;
1017234982Sdim    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
1018234982Sdim  }
1019234982Sdim
1020234982Sdim  case Expr::CXXDeleteExprClass: {
1021234982Sdim    CanThrowResult CT;
1022234982Sdim    QualType DTy = cast<CXXDeleteExpr>(E)->getDestroyedType();
1023234982Sdim    if (DTy.isNull() || DTy->isDependentType()) {
1024234982Sdim      CT = CT_Dependent;
1025234982Sdim    } else {
1026234982Sdim      CT = canCalleeThrow(*this, E,
1027234982Sdim                          cast<CXXDeleteExpr>(E)->getOperatorDelete());
1028234982Sdim      if (const RecordType *RT = DTy->getAs<RecordType>()) {
1029234982Sdim        const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
1030261991Sdim        const CXXDestructorDecl *DD = RD->getDestructor();
1031261991Sdim        if (DD)
1032261991Sdim          CT = mergeCanThrow(CT, canCalleeThrow(*this, E, DD));
1033234982Sdim      }
1034234982Sdim      if (CT == CT_Can)
1035234982Sdim        return CT;
1036234982Sdim    }
1037234982Sdim    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
1038234982Sdim  }
1039234982Sdim
1040234982Sdim  case Expr::CXXBindTemporaryExprClass: {
1041234982Sdim    // The bound temporary has to be destroyed again, which might throw.
1042234982Sdim    CanThrowResult CT = canCalleeThrow(*this, E,
1043234982Sdim      cast<CXXBindTemporaryExpr>(E)->getTemporary()->getDestructor());
1044234982Sdim    if (CT == CT_Can)
1045234982Sdim      return CT;
1046234982Sdim    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
1047234982Sdim  }
1048234982Sdim
1049234982Sdim    // ObjC message sends are like function calls, but never have exception
1050234982Sdim    // specs.
1051234982Sdim  case Expr::ObjCMessageExprClass:
1052234982Sdim  case Expr::ObjCPropertyRefExprClass:
1053234982Sdim  case Expr::ObjCSubscriptRefExprClass:
1054234982Sdim    return CT_Can;
1055234982Sdim
1056234982Sdim    // All the ObjC literals that are implemented as calls are
1057234982Sdim    // potentially throwing unless we decide to close off that
1058234982Sdim    // possibility.
1059234982Sdim  case Expr::ObjCArrayLiteralClass:
1060234982Sdim  case Expr::ObjCDictionaryLiteralClass:
1061239462Sdim  case Expr::ObjCBoxedExprClass:
1062234982Sdim    return CT_Can;
1063234982Sdim
1064234982Sdim    // Many other things have subexpressions, so we have to test those.
1065234982Sdim    // Some are simple:
1066296417Sdim  case Expr::CoawaitExprClass:
1067234982Sdim  case Expr::ConditionalOperatorClass:
1068234982Sdim  case Expr::CompoundLiteralExprClass:
1069296417Sdim  case Expr::CoyieldExprClass:
1070234982Sdim  case Expr::CXXConstCastExprClass:
1071234982Sdim  case Expr::CXXReinterpretCastExprClass:
1072261991Sdim  case Expr::CXXStdInitializerListExprClass:
1073234982Sdim  case Expr::DesignatedInitExprClass:
1074288943Sdim  case Expr::DesignatedInitUpdateExprClass:
1075234982Sdim  case Expr::ExprWithCleanupsClass:
1076234982Sdim  case Expr::ExtVectorElementExprClass:
1077234982Sdim  case Expr::InitListExprClass:
1078234982Sdim  case Expr::MemberExprClass:
1079234982Sdim  case Expr::ObjCIsaExprClass:
1080234982Sdim  case Expr::ObjCIvarRefExprClass:
1081234982Sdim  case Expr::ParenExprClass:
1082234982Sdim  case Expr::ParenListExprClass:
1083234982Sdim  case Expr::ShuffleVectorExprClass:
1084261991Sdim  case Expr::ConvertVectorExprClass:
1085234982Sdim  case Expr::VAArgExprClass:
1086234982Sdim    return canSubExprsThrow(*this, E);
1087234982Sdim
1088234982Sdim    // Some might be dependent for other reasons.
1089234982Sdim  case Expr::ArraySubscriptExprClass:
1090296417Sdim  case Expr::OMPArraySectionExprClass:
1091234982Sdim  case Expr::BinaryOperatorClass:
1092234982Sdim  case Expr::CompoundAssignOperatorClass:
1093234982Sdim  case Expr::CStyleCastExprClass:
1094234982Sdim  case Expr::CXXStaticCastExprClass:
1095234982Sdim  case Expr::CXXFunctionalCastExprClass:
1096234982Sdim  case Expr::ImplicitCastExprClass:
1097234982Sdim  case Expr::MaterializeTemporaryExprClass:
1098234982Sdim  case Expr::UnaryOperatorClass: {
1099234982Sdim    CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot;
1100234982Sdim    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
1101234982Sdim  }
1102234982Sdim
1103234982Sdim    // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms.
1104234982Sdim  case Expr::StmtExprClass:
1105234982Sdim    return CT_Can;
1106234982Sdim
1107251662Sdim  case Expr::CXXDefaultArgExprClass:
1108251662Sdim    return canThrow(cast<CXXDefaultArgExpr>(E)->getExpr());
1109251662Sdim
1110251662Sdim  case Expr::CXXDefaultInitExprClass:
1111251662Sdim    return canThrow(cast<CXXDefaultInitExpr>(E)->getExpr());
1112251662Sdim
1113234982Sdim  case Expr::ChooseExprClass:
1114234982Sdim    if (E->isTypeDependent() || E->isValueDependent())
1115234982Sdim      return CT_Dependent;
1116261991Sdim    return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr());
1117234982Sdim
1118234982Sdim  case Expr::GenericSelectionExprClass:
1119234982Sdim    if (cast<GenericSelectionExpr>(E)->isResultDependent())
1120234982Sdim      return CT_Dependent;
1121234982Sdim    return canThrow(cast<GenericSelectionExpr>(E)->getResultExpr());
1122234982Sdim
1123234982Sdim    // Some expressions are always dependent.
1124234982Sdim  case Expr::CXXDependentScopeMemberExprClass:
1125234982Sdim  case Expr::CXXUnresolvedConstructExprClass:
1126234982Sdim  case Expr::DependentScopeDeclRefExprClass:
1127280031Sdim  case Expr::CXXFoldExprClass:
1128234982Sdim    return CT_Dependent;
1129234982Sdim
1130234982Sdim  case Expr::AsTypeExprClass:
1131234982Sdim  case Expr::BinaryConditionalOperatorClass:
1132234982Sdim  case Expr::BlockExprClass:
1133234982Sdim  case Expr::CUDAKernelCallExprClass:
1134234982Sdim  case Expr::DeclRefExprClass:
1135234982Sdim  case Expr::ObjCBridgedCastExprClass:
1136234982Sdim  case Expr::ObjCIndirectCopyRestoreExprClass:
1137234982Sdim  case Expr::ObjCProtocolExprClass:
1138234982Sdim  case Expr::ObjCSelectorExprClass:
1139234982Sdim  case Expr::OffsetOfExprClass:
1140234982Sdim  case Expr::PackExpansionExprClass:
1141234982Sdim  case Expr::PseudoObjectExprClass:
1142234982Sdim  case Expr::SubstNonTypeTemplateParmExprClass:
1143234982Sdim  case Expr::SubstNonTypeTemplateParmPackExprClass:
1144243830Sdim  case Expr::FunctionParmPackExprClass:
1145234982Sdim  case Expr::UnaryExprOrTypeTraitExprClass:
1146234982Sdim  case Expr::UnresolvedLookupExprClass:
1147234982Sdim  case Expr::UnresolvedMemberExprClass:
1148280031Sdim  case Expr::TypoExprClass:
1149234982Sdim    // FIXME: Can any of the above throw?  If so, when?
1150234982Sdim    return CT_Cannot;
1151234982Sdim
1152234982Sdim  case Expr::AddrLabelExprClass:
1153234982Sdim  case Expr::ArrayTypeTraitExprClass:
1154234982Sdim  case Expr::AtomicExprClass:
1155234982Sdim  case Expr::TypeTraitExprClass:
1156234982Sdim  case Expr::CXXBoolLiteralExprClass:
1157234982Sdim  case Expr::CXXNoexceptExprClass:
1158234982Sdim  case Expr::CXXNullPtrLiteralExprClass:
1159234982Sdim  case Expr::CXXPseudoDestructorExprClass:
1160234982Sdim  case Expr::CXXScalarValueInitExprClass:
1161234982Sdim  case Expr::CXXThisExprClass:
1162234982Sdim  case Expr::CXXUuidofExprClass:
1163234982Sdim  case Expr::CharacterLiteralClass:
1164234982Sdim  case Expr::ExpressionTraitExprClass:
1165234982Sdim  case Expr::FloatingLiteralClass:
1166234982Sdim  case Expr::GNUNullExprClass:
1167234982Sdim  case Expr::ImaginaryLiteralClass:
1168234982Sdim  case Expr::ImplicitValueInitExprClass:
1169234982Sdim  case Expr::IntegerLiteralClass:
1170288943Sdim  case Expr::NoInitExprClass:
1171234982Sdim  case Expr::ObjCEncodeExprClass:
1172234982Sdim  case Expr::ObjCStringLiteralClass:
1173234982Sdim  case Expr::ObjCBoolLiteralExprClass:
1174234982Sdim  case Expr::OpaqueValueExprClass:
1175234982Sdim  case Expr::PredefinedExprClass:
1176234982Sdim  case Expr::SizeOfPackExprClass:
1177234982Sdim  case Expr::StringLiteralClass:
1178234982Sdim    // These expressions can never throw.
1179234982Sdim    return CT_Cannot;
1180234982Sdim
1181251662Sdim  case Expr::MSPropertyRefExprClass:
1182296417Sdim  case Expr::MSPropertySubscriptExprClass:
1183251662Sdim    llvm_unreachable("Invalid class for expression");
1184251662Sdim
1185234982Sdim#define STMT(CLASS, PARENT) case Expr::CLASS##Class:
1186234982Sdim#define STMT_RANGE(Base, First, Last)
1187234982Sdim#define LAST_STMT_RANGE(BASE, FIRST, LAST)
1188234982Sdim#define EXPR(CLASS, PARENT)
1189234982Sdim#define ABSTRACT_STMT(STMT)
1190234982Sdim#include "clang/AST/StmtNodes.inc"
1191234982Sdim  case Expr::NoStmtClass:
1192234982Sdim    llvm_unreachable("Invalid class for expression");
1193234982Sdim  }
1194234982Sdim  llvm_unreachable("Bogus StmtClass");
1195234982Sdim}
1196234982Sdim
1197198092Srdivacky} // end namespace clang
1198