| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 1 | //===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===// | 
|  | 2 | // | 
| Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame] | 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | 4 | // See https://llvm.org/LICENSE.txt for license information. | 
|  | 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 6 | // | 
|  | 7 | //===----------------------------------------------------------------------===// | 
|  | 8 | // | 
|  | 9 | // This file provides Sema routines for C++ exception specification testing. | 
|  | 10 | // | 
|  | 11 | //===----------------------------------------------------------------------===// | 
|  | 12 |  | 
| John McCall | 8302463 | 2010-08-25 22:03:47 +0000 | [diff] [blame] | 13 | #include "clang/Sema/SemaInternal.h" | 
| Richard Smith | 564417a | 2014-03-20 21:47:22 +0000 | [diff] [blame] | 14 | #include "clang/AST/ASTMutationListener.h" | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 15 | #include "clang/AST/CXXInheritance.h" | 
|  | 16 | #include "clang/AST/Expr.h" | 
|  | 17 | #include "clang/AST/ExprCXX.h" | 
| Douglas Gregor | d6bc5e6 | 2010-03-24 07:14:45 +0000 | [diff] [blame] | 18 | #include "clang/AST/TypeLoc.h" | 
| Douglas Gregor | f40863c | 2010-02-12 07:32:17 +0000 | [diff] [blame] | 19 | #include "clang/Basic/Diagnostic.h" | 
|  | 20 | #include "clang/Basic/SourceManager.h" | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 21 | #include "llvm/ADT/SmallPtrSet.h" | 
| Benjamin Kramer | 4903802 | 2012-02-04 13:45:25 +0000 | [diff] [blame] | 22 | #include "llvm/ADT/SmallString.h" | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 23 |  | 
|  | 24 | namespace clang { | 
|  | 25 |  | 
|  | 26 | static const FunctionProtoType *GetUnderlyingFunction(QualType T) | 
|  | 27 | { | 
|  | 28 | if (const PointerType *PtrTy = T->getAs<PointerType>()) | 
|  | 29 | T = PtrTy->getPointeeType(); | 
|  | 30 | else if (const ReferenceType *RefTy = T->getAs<ReferenceType>()) | 
|  | 31 | T = RefTy->getPointeeType(); | 
| Sebastian Redl | 075b21d | 2009-10-14 14:38:54 +0000 | [diff] [blame] | 32 | else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>()) | 
|  | 33 | T = MPTy->getPointeeType(); | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 34 | return T->getAs<FunctionProtoType>(); | 
|  | 35 | } | 
|  | 36 |  | 
| Richard Smith | 6403e93 | 2014-11-14 00:37:55 +0000 | [diff] [blame] | 37 | /// HACK: libstdc++ has a bug where it shadows std::swap with a member | 
|  | 38 | /// swap function then tries to call std::swap unqualified from the exception | 
|  | 39 | /// specification of that function. This function detects whether we're in | 
|  | 40 | /// such a case and turns off delay-parsing of exception specifications. | 
|  | 41 | bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) { | 
|  | 42 | auto *RD = dyn_cast<CXXRecordDecl>(CurContext); | 
|  | 43 |  | 
|  | 44 | // All the problem cases are member functions named "swap" within class | 
| Richard Smith | 6289546 | 2016-10-19 23:47:37 +0000 | [diff] [blame] | 45 | // templates declared directly within namespace std or std::__debug or | 
|  | 46 | // std::__profile. | 
|  | 47 | if (!RD || !RD->getIdentifier() || !RD->getDescribedClassTemplate() || | 
| Richard Smith | 6403e93 | 2014-11-14 00:37:55 +0000 | [diff] [blame] | 48 | !D.getIdentifier() || !D.getIdentifier()->isStr("swap")) | 
|  | 49 | return false; | 
|  | 50 |  | 
| Richard Smith | 6289546 | 2016-10-19 23:47:37 +0000 | [diff] [blame] | 51 | auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext()); | 
|  | 52 | if (!ND) | 
|  | 53 | return false; | 
|  | 54 |  | 
|  | 55 | bool IsInStd = ND->isStdNamespace(); | 
|  | 56 | if (!IsInStd) { | 
|  | 57 | // This isn't a direct member of namespace std, but it might still be | 
|  | 58 | // libstdc++'s std::__debug::array or std::__profile::array. | 
|  | 59 | IdentifierInfo *II = ND->getIdentifier(); | 
|  | 60 | if (!II || !(II->isStr("__debug") || II->isStr("__profile")) || | 
|  | 61 | !ND->isInStdNamespace()) | 
|  | 62 | return false; | 
|  | 63 | } | 
|  | 64 |  | 
| Richard Smith | 6403e93 | 2014-11-14 00:37:55 +0000 | [diff] [blame] | 65 | // Only apply this hack within a system header. | 
| Stephen Kelly | f2ceec4 | 2018-08-09 21:08:08 +0000 | [diff] [blame] | 66 | if (!Context.getSourceManager().isInSystemHeader(D.getBeginLoc())) | 
| Richard Smith | 6403e93 | 2014-11-14 00:37:55 +0000 | [diff] [blame] | 67 | return false; | 
|  | 68 |  | 
|  | 69 | return llvm::StringSwitch<bool>(RD->getIdentifier()->getName()) | 
|  | 70 | .Case("array", true) | 
| Richard Smith | 6289546 | 2016-10-19 23:47:37 +0000 | [diff] [blame] | 71 | .Case("pair", IsInStd) | 
|  | 72 | .Case("priority_queue", IsInStd) | 
|  | 73 | .Case("stack", IsInStd) | 
|  | 74 | .Case("queue", IsInStd) | 
| Richard Smith | 6403e93 | 2014-11-14 00:37:55 +0000 | [diff] [blame] | 75 | .Default(false); | 
|  | 76 | } | 
|  | 77 |  | 
| Richard Smith | eaf11ad | 2018-05-03 03:58:32 +0000 | [diff] [blame] | 78 | ExprResult Sema::ActOnNoexceptSpec(SourceLocation NoexceptLoc, | 
|  | 79 | Expr *NoexceptExpr, | 
|  | 80 | ExceptionSpecificationType &EST) { | 
|  | 81 | // FIXME: This is bogus, a noexcept expression is not a condition. | 
|  | 82 | ExprResult Converted = CheckBooleanCondition(NoexceptLoc, NoexceptExpr); | 
|  | 83 | if (Converted.isInvalid()) | 
|  | 84 | return Converted; | 
|  | 85 |  | 
|  | 86 | if (Converted.get()->isValueDependent()) { | 
|  | 87 | EST = EST_DependentNoexcept; | 
|  | 88 | return Converted; | 
|  | 89 | } | 
|  | 90 |  | 
|  | 91 | llvm::APSInt Result; | 
|  | 92 | Converted = VerifyIntegerConstantExpression( | 
|  | 93 | Converted.get(), &Result, | 
|  | 94 | diag::err_noexcept_needs_constant_expression, | 
|  | 95 | /*AllowFold*/ false); | 
|  | 96 | if (!Converted.isInvalid()) | 
|  | 97 | EST = !Result ? EST_NoexceptFalse : EST_NoexceptTrue; | 
|  | 98 | return Converted; | 
|  | 99 | } | 
|  | 100 |  | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 101 | /// CheckSpecifiedExceptionType - Check if the given type is valid in an | 
|  | 102 | /// exception specification. Incomplete types, or pointers to incomplete types | 
|  | 103 | /// other than void are not allowed. | 
| Richard Smith | 8606d75 | 2012-11-28 22:33:28 +0000 | [diff] [blame] | 104 | /// | 
|  | 105 | /// \param[in,out] T  The exception type. This will be decayed to a pointer type | 
|  | 106 | ///                   when the input is an array or a function type. | 
| Craig Topper | e335f25 | 2015-10-04 04:53:55 +0000 | [diff] [blame] | 107 | bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) { | 
| Richard Smith | a118c6a | 2012-11-28 22:52:42 +0000 | [diff] [blame] | 108 | // C++11 [except.spec]p2: | 
|  | 109 | //   A type cv T, "array of T", or "function returning T" denoted | 
| Richard Smith | 8606d75 | 2012-11-28 22:33:28 +0000 | [diff] [blame] | 110 | //   in an exception-specification is adjusted to type T, "pointer to T", or | 
|  | 111 | //   "pointer to function returning T", respectively. | 
| Richard Smith | a118c6a | 2012-11-28 22:52:42 +0000 | [diff] [blame] | 112 | // | 
|  | 113 | // We also apply this rule in C++98. | 
| Richard Smith | 8606d75 | 2012-11-28 22:33:28 +0000 | [diff] [blame] | 114 | if (T->isArrayType()) | 
|  | 115 | T = Context.getArrayDecayedType(T); | 
|  | 116 | else if (T->isFunctionType()) | 
|  | 117 | T = Context.getPointerType(T); | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 118 |  | 
| Richard Smith | a118c6a | 2012-11-28 22:52:42 +0000 | [diff] [blame] | 119 | int Kind = 0; | 
| Richard Smith | 8606d75 | 2012-11-28 22:33:28 +0000 | [diff] [blame] | 120 | QualType PointeeT = T; | 
| Richard Smith | a118c6a | 2012-11-28 22:52:42 +0000 | [diff] [blame] | 121 | if (const PointerType *PT = T->getAs<PointerType>()) { | 
|  | 122 | PointeeT = PT->getPointeeType(); | 
|  | 123 | Kind = 1; | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 124 |  | 
| Richard Smith | a118c6a | 2012-11-28 22:52:42 +0000 | [diff] [blame] | 125 | // cv void* is explicitly permitted, despite being a pointer to an | 
|  | 126 | // incomplete type. | 
|  | 127 | if (PointeeT->isVoidType()) | 
|  | 128 | return false; | 
|  | 129 | } else if (const ReferenceType *RT = T->getAs<ReferenceType>()) { | 
|  | 130 | PointeeT = RT->getPointeeType(); | 
|  | 131 | Kind = 2; | 
| Richard Smith | 8606d75 | 2012-11-28 22:33:28 +0000 | [diff] [blame] | 132 |  | 
| Richard Smith | a118c6a | 2012-11-28 22:52:42 +0000 | [diff] [blame] | 133 | if (RT->isRValueReferenceType()) { | 
|  | 134 | // C++11 [except.spec]p2: | 
|  | 135 | //   A type denoted in an exception-specification shall not denote [...] | 
|  | 136 | //   an rvalue reference type. | 
|  | 137 | Diag(Range.getBegin(), diag::err_rref_in_exception_spec) | 
|  | 138 | << T << Range; | 
|  | 139 | return true; | 
|  | 140 | } | 
|  | 141 | } | 
|  | 142 |  | 
|  | 143 | // C++11 [except.spec]p2: | 
|  | 144 | //   A type denoted in an exception-specification shall not denote an | 
|  | 145 | //   incomplete type other than a class currently being defined [...]. | 
|  | 146 | //   A type denoted in an exception-specification shall not denote a | 
|  | 147 | //   pointer or reference to an incomplete type, other than (cv) void* or a | 
|  | 148 | //   pointer or reference to a class currently being defined. | 
| David Majnemer | b2b0da4 | 2016-06-10 18:24:41 +0000 | [diff] [blame] | 149 | // In Microsoft mode, downgrade this to a warning. | 
|  | 150 | unsigned DiagID = diag::err_incomplete_in_exception_spec; | 
| David Majnemer | 5d321e6 | 2016-06-11 01:25:04 +0000 | [diff] [blame] | 151 | bool ReturnValueOnError = true; | 
| Reid Kleckner | 39aa895 | 2019-08-27 17:52:03 +0000 | [diff] [blame] | 152 | if (getLangOpts().MSVCCompat) { | 
| David Majnemer | b2b0da4 | 2016-06-10 18:24:41 +0000 | [diff] [blame] | 153 | DiagID = diag::ext_incomplete_in_exception_spec; | 
| David Majnemer | 5d321e6 | 2016-06-11 01:25:04 +0000 | [diff] [blame] | 154 | ReturnValueOnError = false; | 
|  | 155 | } | 
| Richard Smith | a118c6a | 2012-11-28 22:52:42 +0000 | [diff] [blame] | 156 | if (!(PointeeT->isRecordType() && | 
| Simon Pilgrim | 1cd399c | 2019-10-03 11:22:48 +0000 | [diff] [blame] | 157 | PointeeT->castAs<RecordType>()->isBeingDefined()) && | 
| David Majnemer | b2b0da4 | 2016-06-10 18:24:41 +0000 | [diff] [blame] | 158 | RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range)) | 
| David Majnemer | 5d321e6 | 2016-06-11 01:25:04 +0000 | [diff] [blame] | 159 | return ReturnValueOnError; | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 160 |  | 
|  | 161 | return false; | 
|  | 162 | } | 
|  | 163 |  | 
|  | 164 | /// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer | 
|  | 165 | /// to member to a function with an exception specification. This means that | 
|  | 166 | /// it is invalid to add another level of indirection. | 
|  | 167 | bool Sema::CheckDistantExceptionSpec(QualType T) { | 
| Richard Smith | 3c4f8d2 | 2016-10-16 17:54:23 +0000 | [diff] [blame] | 168 | // C++17 removes this rule in favor of putting exception specifications into | 
|  | 169 | // the type system. | 
| Aaron Ballman | c351fba | 2017-12-04 20:27:34 +0000 | [diff] [blame] | 170 | if (getLangOpts().CPlusPlus17) | 
| Richard Smith | 3c4f8d2 | 2016-10-16 17:54:23 +0000 | [diff] [blame] | 171 | return false; | 
|  | 172 |  | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 173 | if (const PointerType *PT = T->getAs<PointerType>()) | 
|  | 174 | T = PT->getPointeeType(); | 
|  | 175 | else if (const MemberPointerType *PT = T->getAs<MemberPointerType>()) | 
|  | 176 | T = PT->getPointeeType(); | 
|  | 177 | else | 
|  | 178 | return false; | 
|  | 179 |  | 
|  | 180 | const FunctionProtoType *FnT = T->getAs<FunctionProtoType>(); | 
|  | 181 | if (!FnT) | 
|  | 182 | return false; | 
|  | 183 |  | 
|  | 184 | return FnT->hasExceptionSpec(); | 
|  | 185 | } | 
|  | 186 |  | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 187 | const FunctionProtoType * | 
|  | 188 | Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { | 
| Richard Smith | 0b3a462 | 2014-11-13 20:01:57 +0000 | [diff] [blame] | 189 | if (FPT->getExceptionSpecType() == EST_Unparsed) { | 
|  | 190 | Diag(Loc, diag::err_exception_spec_not_parsed); | 
|  | 191 | return nullptr; | 
|  | 192 | } | 
|  | 193 |  | 
| Richard Smith | d3b5c908 | 2012-07-27 04:22:15 +0000 | [diff] [blame] | 194 | if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 195 | return FPT; | 
|  | 196 |  | 
|  | 197 | FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl(); | 
|  | 198 | const FunctionProtoType *SourceFPT = | 
|  | 199 | SourceDecl->getType()->castAs<FunctionProtoType>(); | 
|  | 200 |  | 
| Richard Smith | d3b5c908 | 2012-07-27 04:22:15 +0000 | [diff] [blame] | 201 | // If the exception specification has already been resolved, just return it. | 
|  | 202 | if (!isUnresolvedExceptionSpec(SourceFPT->getExceptionSpecType())) | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 203 | return SourceFPT; | 
|  | 204 |  | 
| Richard Smith | d3b5c908 | 2012-07-27 04:22:15 +0000 | [diff] [blame] | 205 | // Compute or instantiate the exception specification now. | 
| Richard Smith | 3901dfe | 2013-03-27 00:22:47 +0000 | [diff] [blame] | 206 | if (SourceFPT->getExceptionSpecType() == EST_Unevaluated) | 
| Richard Smith | d3b5c908 | 2012-07-27 04:22:15 +0000 | [diff] [blame] | 207 | EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl)); | 
|  | 208 | else | 
|  | 209 | InstantiateExceptionSpec(Loc, SourceDecl); | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 210 |  | 
| Davide Italiano | 922b702 | 2015-07-25 01:19:32 +0000 | [diff] [blame] | 211 | const FunctionProtoType *Proto = | 
|  | 212 | SourceDecl->getType()->castAs<FunctionProtoType>(); | 
|  | 213 | if (Proto->getExceptionSpecType() == clang::EST_Unparsed) { | 
|  | 214 | Diag(Loc, diag::err_exception_spec_not_parsed); | 
|  | 215 | Proto = nullptr; | 
|  | 216 | } | 
|  | 217 | return Proto; | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 218 | } | 
|  | 219 |  | 
| Richard Smith | 8acb428 | 2014-07-31 21:57:55 +0000 | [diff] [blame] | 220 | void | 
|  | 221 | Sema::UpdateExceptionSpec(FunctionDecl *FD, | 
|  | 222 | const FunctionProtoType::ExceptionSpecInfo &ESI) { | 
| Richard Smith | 564417a | 2014-03-20 21:47:22 +0000 | [diff] [blame] | 223 | // If we've fully resolved the exception specification, notify listeners. | 
| Richard Smith | 8acb428 | 2014-07-31 21:57:55 +0000 | [diff] [blame] | 224 | if (!isUnresolvedExceptionSpec(ESI.Type)) | 
| Richard Smith | 564417a | 2014-03-20 21:47:22 +0000 | [diff] [blame] | 225 | if (auto *Listener = getASTMutationListener()) | 
|  | 226 | Listener->ResolvedExceptionSpec(FD); | 
| Richard Smith | 9e2341d | 2015-03-23 03:25:59 +0000 | [diff] [blame] | 227 |  | 
| George Burgess IV | 00f70bd | 2018-03-01 05:43:23 +0000 | [diff] [blame] | 228 | for (FunctionDecl *Redecl : FD->redecls()) | 
|  | 229 | Context.adjustExceptionSpec(Redecl, ESI); | 
| Richard Smith | 564417a | 2014-03-20 21:47:22 +0000 | [diff] [blame] | 230 | } | 
|  | 231 |  | 
| Richard Smith | 5159bbad | 2018-09-05 22:30:37 +0000 | [diff] [blame] | 232 | static bool exceptionSpecNotKnownYet(const FunctionDecl *FD) { | 
|  | 233 | auto *MD = dyn_cast<CXXMethodDecl>(FD); | 
|  | 234 | if (!MD) | 
|  | 235 | return false; | 
|  | 236 |  | 
|  | 237 | auto EST = MD->getType()->castAs<FunctionProtoType>()->getExceptionSpecType(); | 
|  | 238 | return EST == EST_Unparsed || | 
|  | 239 | (EST == EST_Unevaluated && MD->getParent()->isBeingDefined()); | 
| Simon Pilgrim | 58310ec | 2018-09-06 15:16:17 +0000 | [diff] [blame] | 240 | } | 
| Richard Smith | 5159bbad | 2018-09-05 22:30:37 +0000 | [diff] [blame] | 241 |  | 
| Richard Smith | 13b40bc | 2016-11-30 00:13:55 +0000 | [diff] [blame] | 242 | static bool CheckEquivalentExceptionSpecImpl( | 
|  | 243 | Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID, | 
|  | 244 | const FunctionProtoType *Old, SourceLocation OldLoc, | 
|  | 245 | const FunctionProtoType *New, SourceLocation NewLoc, | 
|  | 246 | bool *MissingExceptionSpecification = nullptr, | 
|  | 247 | bool *MissingEmptyExceptionSpecification = nullptr, | 
|  | 248 | bool AllowNoexceptAllMatchWithNoSpec = false, bool IsOperatorNew = false); | 
|  | 249 |  | 
| Richard Smith | 66f3ac9 | 2012-10-20 08:26:51 +0000 | [diff] [blame] | 250 | /// Determine whether a function has an implicitly-generated exception | 
| Richard Smith | 1ee6352 | 2012-10-16 23:30:16 +0000 | [diff] [blame] | 251 | /// specification. | 
| Richard Smith | 66f3ac9 | 2012-10-20 08:26:51 +0000 | [diff] [blame] | 252 | static bool hasImplicitExceptionSpec(FunctionDecl *Decl) { | 
|  | 253 | if (!isa<CXXDestructorDecl>(Decl) && | 
|  | 254 | Decl->getDeclName().getCXXOverloadedOperator() != OO_Delete && | 
|  | 255 | Decl->getDeclName().getCXXOverloadedOperator() != OO_Array_Delete) | 
|  | 256 | return false; | 
| Richard Smith | 1ee6352 | 2012-10-16 23:30:16 +0000 | [diff] [blame] | 257 |  | 
| Richard Smith | c7fb225 | 2014-02-07 22:51:16 +0000 | [diff] [blame] | 258 | // For a function that the user didn't declare: | 
|  | 259 | //  - if this is a destructor, its exception specification is implicit. | 
|  | 260 | //  - if this is 'operator delete' or 'operator delete[]', the exception | 
|  | 261 | //    specification is as-if an explicit exception specification was given | 
|  | 262 | //    (per [basic.stc.dynamic]p2). | 
| Richard Smith | 66f3ac9 | 2012-10-20 08:26:51 +0000 | [diff] [blame] | 263 | if (!Decl->getTypeSourceInfo()) | 
| Richard Smith | c7fb225 | 2014-02-07 22:51:16 +0000 | [diff] [blame] | 264 | return isa<CXXDestructorDecl>(Decl); | 
| Richard Smith | 66f3ac9 | 2012-10-20 08:26:51 +0000 | [diff] [blame] | 265 |  | 
| Simon Pilgrim | afb163f | 2019-10-21 18:28:31 +0000 | [diff] [blame] | 266 | auto *Ty = Decl->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>(); | 
| Richard Smith | 66f3ac9 | 2012-10-20 08:26:51 +0000 | [diff] [blame] | 267 | return !Ty->hasExceptionSpec(); | 
| Richard Smith | 1ee6352 | 2012-10-16 23:30:16 +0000 | [diff] [blame] | 268 | } | 
|  | 269 |  | 
| Douglas Gregor | f40863c | 2010-02-12 07:32:17 +0000 | [diff] [blame] | 270 | bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { | 
| Aaron Ballman | c351fba | 2017-12-04 20:27:34 +0000 | [diff] [blame] | 271 | // Just completely ignore this under -fno-exceptions prior to C++17. | 
|  | 272 | // In C++17 onwards, the exception specification is part of the type and | 
| Richard Smith | 13b40bc | 2016-11-30 00:13:55 +0000 | [diff] [blame] | 273 | // we will diagnose mismatches anyway, so it's better to check for them here. | 
| Aaron Ballman | c351fba | 2017-12-04 20:27:34 +0000 | [diff] [blame] | 274 | if (!getLangOpts().CXXExceptions && !getLangOpts().CPlusPlus17) | 
| Richard Smith | 13b40bc | 2016-11-30 00:13:55 +0000 | [diff] [blame] | 275 | return false; | 
|  | 276 |  | 
| Sebastian Redl | cb5dd00 | 2011-03-15 19:52:30 +0000 | [diff] [blame] | 277 | OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator(); | 
|  | 278 | bool IsOperatorNew = OO == OO_New || OO == OO_Array_New; | 
| Douglas Gregor | d6bc5e6 | 2010-03-24 07:14:45 +0000 | [diff] [blame] | 279 | bool MissingExceptionSpecification = false; | 
| Douglas Gregor | f40863c | 2010-02-12 07:32:17 +0000 | [diff] [blame] | 280 | bool MissingEmptyExceptionSpecification = false; | 
| Hans Wennborg | 39a509a | 2014-02-05 02:37:58 +0000 | [diff] [blame] | 281 |  | 
| Francois Pichet | 13b4e68 | 2011-03-19 23:05:18 +0000 | [diff] [blame] | 282 | unsigned DiagID = diag::err_mismatched_exception_spec; | 
| Hans Wennborg | 39a509a | 2014-02-05 02:37:58 +0000 | [diff] [blame] | 283 | bool ReturnValueOnError = true; | 
| Reid Kleckner | 39aa895 | 2019-08-27 17:52:03 +0000 | [diff] [blame] | 284 | if (getLangOpts().MSVCCompat) { | 
| Richard Smith | 1b98ccc | 2014-07-19 01:39:17 +0000 | [diff] [blame] | 285 | DiagID = diag::ext_mismatched_exception_spec; | 
| Hans Wennborg | 39a509a | 2014-02-05 02:37:58 +0000 | [diff] [blame] | 286 | ReturnValueOnError = false; | 
|  | 287 | } | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 288 |  | 
| Richard Smith | 5159bbad | 2018-09-05 22:30:37 +0000 | [diff] [blame] | 289 | // If we're befriending a member function of a class that's currently being | 
|  | 290 | // defined, we might not be able to work out its exception specification yet. | 
|  | 291 | // If not, defer the check until later. | 
|  | 292 | if (exceptionSpecNotKnownYet(Old) || exceptionSpecNotKnownYet(New)) { | 
|  | 293 | DelayedEquivalentExceptionSpecChecks.push_back({New, Old}); | 
|  | 294 | return false; | 
|  | 295 | } | 
|  | 296 |  | 
| Richard Smith | 1ee6352 | 2012-10-16 23:30:16 +0000 | [diff] [blame] | 297 | // Check the types as written: they must match before any exception | 
|  | 298 | // specification adjustment is applied. | 
| Richard Smith | 13b40bc | 2016-11-30 00:13:55 +0000 | [diff] [blame] | 299 | if (!CheckEquivalentExceptionSpecImpl( | 
|  | 300 | *this, PDiag(DiagID), PDiag(diag::note_previous_declaration), | 
| Richard Smith | 66f3ac9 | 2012-10-20 08:26:51 +0000 | [diff] [blame] | 301 | Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), | 
|  | 302 | New->getType()->getAs<FunctionProtoType>(), New->getLocation(), | 
| Richard Smith | 1ee6352 | 2012-10-16 23:30:16 +0000 | [diff] [blame] | 303 | &MissingExceptionSpecification, &MissingEmptyExceptionSpecification, | 
| Richard Smith | 66f3ac9 | 2012-10-20 08:26:51 +0000 | [diff] [blame] | 304 | /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) { | 
|  | 305 | // C++11 [except.spec]p4 [DR1492]: | 
|  | 306 | //   If a declaration of a function has an implicit | 
|  | 307 | //   exception-specification, other declarations of the function shall | 
|  | 308 | //   not specify an exception-specification. | 
| Richard Smith | e3ea001 | 2016-08-31 20:38:32 +0000 | [diff] [blame] | 309 | if (getLangOpts().CPlusPlus11 && getLangOpts().CXXExceptions && | 
| Richard Smith | 66f3ac9 | 2012-10-20 08:26:51 +0000 | [diff] [blame] | 310 | hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) { | 
|  | 311 | Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch) | 
|  | 312 | << hasImplicitExceptionSpec(Old); | 
| Yaron Keren | 8b56366 | 2015-10-03 10:46:20 +0000 | [diff] [blame] | 313 | if (Old->getLocation().isValid()) | 
| Richard Smith | 66f3ac9 | 2012-10-20 08:26:51 +0000 | [diff] [blame] | 314 | Diag(Old->getLocation(), diag::note_previous_declaration); | 
|  | 315 | } | 
| Douglas Gregor | f40863c | 2010-02-12 07:32:17 +0000 | [diff] [blame] | 316 | return false; | 
| Richard Smith | 66f3ac9 | 2012-10-20 08:26:51 +0000 | [diff] [blame] | 317 | } | 
| Douglas Gregor | f40863c | 2010-02-12 07:32:17 +0000 | [diff] [blame] | 318 |  | 
| Eli Friedman | 96dbf6f | 2013-06-25 00:46:32 +0000 | [diff] [blame] | 319 | // The failure was something other than an missing exception | 
| Hans Wennborg | 39a509a | 2014-02-05 02:37:58 +0000 | [diff] [blame] | 320 | // specification; return an error, except in MS mode where this is a warning. | 
| Eli Friedman | 96dbf6f | 2013-06-25 00:46:32 +0000 | [diff] [blame] | 321 | if (!MissingExceptionSpecification) | 
| Hans Wennborg | 39a509a | 2014-02-05 02:37:58 +0000 | [diff] [blame] | 322 | return ReturnValueOnError; | 
| Douglas Gregor | f40863c | 2010-02-12 07:32:17 +0000 | [diff] [blame] | 323 |  | 
| Richard Smith | 66f3ac9 | 2012-10-20 08:26:51 +0000 | [diff] [blame] | 324 | const FunctionProtoType *NewProto = | 
| Eli Friedman | 96dbf6f | 2013-06-25 00:46:32 +0000 | [diff] [blame] | 325 | New->getType()->castAs<FunctionProtoType>(); | 
| John McCall | db40c7f | 2010-12-14 08:05:40 +0000 | [diff] [blame] | 326 |  | 
| Douglas Gregor | f40863c | 2010-02-12 07:32:17 +0000 | [diff] [blame] | 327 | // The new function declaration is only missing an empty exception | 
|  | 328 | // specification "throw()". If the throw() specification came from a | 
|  | 329 | // function in a system header that has C linkage, just add an empty | 
| Richard Smith | 836de6b | 2016-12-19 23:59:34 +0000 | [diff] [blame] | 330 | // exception specification to the "new" declaration. Note that C library | 
|  | 331 | // implementations are permitted to add these nothrow exception | 
|  | 332 | // specifications. | 
|  | 333 | // | 
|  | 334 | // Likewise if the old function is a builtin. | 
| John McCall | db40c7f | 2010-12-14 08:05:40 +0000 | [diff] [blame] | 335 | if (MissingEmptyExceptionSpecification && NewProto && | 
| Douglas Gregor | d6bc5e6 | 2010-03-24 07:14:45 +0000 | [diff] [blame] | 336 | (Old->getLocation().isInvalid() || | 
| Richard Smith | 836de6b | 2016-12-19 23:59:34 +0000 | [diff] [blame] | 337 | Context.getSourceManager().isInSystemHeader(Old->getLocation()) || | 
|  | 338 | Old->getBuiltinID()) && | 
| Douglas Gregor | f40863c | 2010-02-12 07:32:17 +0000 | [diff] [blame] | 339 | Old->isExternC()) { | 
| Richard Smith | 8acb428 | 2014-07-31 21:57:55 +0000 | [diff] [blame] | 340 | New->setType(Context.getFunctionType( | 
|  | 341 | NewProto->getReturnType(), NewProto->getParamTypes(), | 
|  | 342 | NewProto->getExtProtoInfo().withExceptionSpec(EST_DynamicNone))); | 
| Douglas Gregor | f40863c | 2010-02-12 07:32:17 +0000 | [diff] [blame] | 343 | return false; | 
|  | 344 | } | 
|  | 345 |  | 
| Eli Friedman | 96dbf6f | 2013-06-25 00:46:32 +0000 | [diff] [blame] | 346 | const FunctionProtoType *OldProto = | 
|  | 347 | Old->getType()->castAs<FunctionProtoType>(); | 
| Douglas Gregor | d6bc5e6 | 2010-03-24 07:14:45 +0000 | [diff] [blame] | 348 |  | 
| Richard Smith | 8acb428 | 2014-07-31 21:57:55 +0000 | [diff] [blame] | 349 | FunctionProtoType::ExceptionSpecInfo ESI = OldProto->getExceptionSpecType(); | 
|  | 350 | if (ESI.Type == EST_Dynamic) { | 
| Richard Smith | eaf11ad | 2018-05-03 03:58:32 +0000 | [diff] [blame] | 351 | // FIXME: What if the exceptions are described in terms of the old | 
|  | 352 | // prototype's parameters? | 
| Richard Smith | 8acb428 | 2014-07-31 21:57:55 +0000 | [diff] [blame] | 353 | ESI.Exceptions = OldProto->exceptions(); | 
| Douglas Gregor | d6bc5e6 | 2010-03-24 07:14:45 +0000 | [diff] [blame] | 354 | } | 
|  | 355 |  | 
| Richard Smith | eaf11ad | 2018-05-03 03:58:32 +0000 | [diff] [blame] | 356 | if (ESI.Type == EST_NoexceptFalse) | 
|  | 357 | ESI.Type = EST_None; | 
|  | 358 | if (ESI.Type == EST_NoexceptTrue) | 
|  | 359 | ESI.Type = EST_BasicNoexcept; | 
|  | 360 |  | 
|  | 361 | // For dependent noexcept, we can't just take the expression from the old | 
|  | 362 | // prototype. It likely contains references to the old prototype's parameters. | 
|  | 363 | if (ESI.Type == EST_DependentNoexcept) { | 
| Richard Smith | a91de37 | 2015-09-30 00:48:50 +0000 | [diff] [blame] | 364 | New->setInvalidDecl(); | 
|  | 365 | } else { | 
|  | 366 | // Update the type of the function with the appropriate exception | 
|  | 367 | // specification. | 
|  | 368 | New->setType(Context.getFunctionType( | 
|  | 369 | NewProto->getReturnType(), NewProto->getParamTypes(), | 
|  | 370 | NewProto->getExtProtoInfo().withExceptionSpec(ESI))); | 
|  | 371 | } | 
|  | 372 |  | 
| Reid Kleckner | 39aa895 | 2019-08-27 17:52:03 +0000 | [diff] [blame] | 373 | if (getLangOpts().MSVCCompat && ESI.Type != EST_DependentNoexcept) { | 
| David Majnemer | 06ce8a4 | 2015-10-20 20:49:21 +0000 | [diff] [blame] | 374 | // Allow missing exception specifications in redeclarations as an extension. | 
|  | 375 | DiagID = diag::ext_ms_missing_exception_specification; | 
|  | 376 | ReturnValueOnError = false; | 
|  | 377 | } else if (New->isReplaceableGlobalAllocationFunction() && | 
| Richard Smith | eaf11ad | 2018-05-03 03:58:32 +0000 | [diff] [blame] | 378 | ESI.Type != EST_DependentNoexcept) { | 
| David Majnemer | 06ce8a4 | 2015-10-20 20:49:21 +0000 | [diff] [blame] | 379 | // Allow missing exception specifications in redeclarations as an extension, | 
|  | 380 | // when declaring a replaceable global allocation function. | 
| Richard Smith | a91de37 | 2015-09-30 00:48:50 +0000 | [diff] [blame] | 381 | DiagID = diag::ext_missing_exception_specification; | 
|  | 382 | ReturnValueOnError = false; | 
| Erich Keane | 54182eb | 2019-05-31 14:26:19 +0000 | [diff] [blame] | 383 | } else if (ESI.Type == EST_NoThrow) { | 
|  | 384 | // Allow missing attribute 'nothrow' in redeclarations, since this is a very | 
|  | 385 | // common omission. | 
|  | 386 | DiagID = diag::ext_missing_exception_specification; | 
|  | 387 | ReturnValueOnError = false; | 
| Richard Smith | a91de37 | 2015-09-30 00:48:50 +0000 | [diff] [blame] | 388 | } else { | 
|  | 389 | DiagID = diag::err_missing_exception_specification; | 
|  | 390 | ReturnValueOnError = true; | 
|  | 391 | } | 
| Eli Friedman | 96dbf6f | 2013-06-25 00:46:32 +0000 | [diff] [blame] | 392 |  | 
|  | 393 | // Warn about the lack of exception specification. | 
|  | 394 | SmallString<128> ExceptionSpecString; | 
|  | 395 | llvm::raw_svector_ostream OS(ExceptionSpecString); | 
|  | 396 | switch (OldProto->getExceptionSpecType()) { | 
|  | 397 | case EST_DynamicNone: | 
|  | 398 | OS << "throw()"; | 
|  | 399 | break; | 
|  | 400 |  | 
|  | 401 | case EST_Dynamic: { | 
|  | 402 | OS << "throw("; | 
|  | 403 | bool OnFirstException = true; | 
| Aaron Ballman | b088fbe | 2014-03-17 15:38:09 +0000 | [diff] [blame] | 404 | for (const auto &E : OldProto->exceptions()) { | 
| Eli Friedman | 96dbf6f | 2013-06-25 00:46:32 +0000 | [diff] [blame] | 405 | if (OnFirstException) | 
|  | 406 | OnFirstException = false; | 
|  | 407 | else | 
|  | 408 | OS << ", "; | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 409 |  | 
| Aaron Ballman | b088fbe | 2014-03-17 15:38:09 +0000 | [diff] [blame] | 410 | OS << E.getAsString(getPrintingPolicy()); | 
| Eli Friedman | 96dbf6f | 2013-06-25 00:46:32 +0000 | [diff] [blame] | 411 | } | 
|  | 412 | OS << ")"; | 
|  | 413 | break; | 
|  | 414 | } | 
|  | 415 |  | 
|  | 416 | case EST_BasicNoexcept: | 
|  | 417 | OS << "noexcept"; | 
|  | 418 | break; | 
|  | 419 |  | 
| Richard Smith | eaf11ad | 2018-05-03 03:58:32 +0000 | [diff] [blame] | 420 | case EST_DependentNoexcept: | 
|  | 421 | case EST_NoexceptFalse: | 
|  | 422 | case EST_NoexceptTrue: | 
| Eli Friedman | 96dbf6f | 2013-06-25 00:46:32 +0000 | [diff] [blame] | 423 | OS << "noexcept("; | 
| Richard Trieu | ddd01ce | 2014-06-09 22:53:25 +0000 | [diff] [blame] | 424 | assert(OldProto->getNoexceptExpr() != nullptr && "Expected non-null Expr"); | 
| Craig Topper | c3ec149 | 2014-05-26 06:22:03 +0000 | [diff] [blame] | 425 | OldProto->getNoexceptExpr()->printPretty(OS, nullptr, getPrintingPolicy()); | 
| Eli Friedman | 96dbf6f | 2013-06-25 00:46:32 +0000 | [diff] [blame] | 426 | OS << ")"; | 
|  | 427 | break; | 
| Erich Keane | 54182eb | 2019-05-31 14:26:19 +0000 | [diff] [blame] | 428 | case EST_NoThrow: | 
|  | 429 | OS <<"__attribute__((nothrow))"; | 
|  | 430 | break; | 
| Erich Keane | 68fa6dd | 2019-05-31 17:00:48 +0000 | [diff] [blame] | 431 | case EST_None: | 
|  | 432 | case EST_MSAny: | 
|  | 433 | case EST_Unevaluated: | 
|  | 434 | case EST_Uninstantiated: | 
|  | 435 | case EST_Unparsed: | 
| Eli Friedman | 96dbf6f | 2013-06-25 00:46:32 +0000 | [diff] [blame] | 436 | llvm_unreachable("This spec type is compatible with none."); | 
|  | 437 | } | 
| Eli Friedman | 96dbf6f | 2013-06-25 00:46:32 +0000 | [diff] [blame] | 438 |  | 
|  | 439 | SourceLocation FixItLoc; | 
|  | 440 | if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) { | 
|  | 441 | TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens(); | 
| Richard Smith | a91de37 | 2015-09-30 00:48:50 +0000 | [diff] [blame] | 442 | // FIXME: Preserve enough information so that we can produce a correct fixit | 
|  | 443 | // location when there is a trailing return type. | 
|  | 444 | if (auto FTLoc = TL.getAs<FunctionProtoTypeLoc>()) | 
|  | 445 | if (!FTLoc.getTypePtr()->hasTrailingReturn()) | 
|  | 446 | FixItLoc = getLocForEndOfToken(FTLoc.getLocalRangeEnd()); | 
| Eli Friedman | 96dbf6f | 2013-06-25 00:46:32 +0000 | [diff] [blame] | 447 | } | 
|  | 448 |  | 
|  | 449 | if (FixItLoc.isInvalid()) | 
| Richard Smith | a91de37 | 2015-09-30 00:48:50 +0000 | [diff] [blame] | 450 | Diag(New->getLocation(), DiagID) | 
| Eli Friedman | 96dbf6f | 2013-06-25 00:46:32 +0000 | [diff] [blame] | 451 | << New << OS.str(); | 
|  | 452 | else { | 
| Richard Smith | a91de37 | 2015-09-30 00:48:50 +0000 | [diff] [blame] | 453 | Diag(New->getLocation(), DiagID) | 
| Eli Friedman | 96dbf6f | 2013-06-25 00:46:32 +0000 | [diff] [blame] | 454 | << New << OS.str() | 
|  | 455 | << FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str()); | 
|  | 456 | } | 
|  | 457 |  | 
| Yaron Keren | 8b56366 | 2015-10-03 10:46:20 +0000 | [diff] [blame] | 458 | if (Old->getLocation().isValid()) | 
| Eli Friedman | 96dbf6f | 2013-06-25 00:46:32 +0000 | [diff] [blame] | 459 | Diag(Old->getLocation(), diag::note_previous_declaration); | 
|  | 460 |  | 
| Richard Smith | a91de37 | 2015-09-30 00:48:50 +0000 | [diff] [blame] | 461 | return ReturnValueOnError; | 
| Douglas Gregor | f40863c | 2010-02-12 07:32:17 +0000 | [diff] [blame] | 462 | } | 
|  | 463 |  | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 464 | /// CheckEquivalentExceptionSpec - Check if the two types have equivalent | 
|  | 465 | /// exception specifications. Exception specifications are equivalent if | 
|  | 466 | /// they allow exactly the same set of exception types. It does not matter how | 
|  | 467 | /// that is achieved. See C++ [except.spec]p2. | 
|  | 468 | bool Sema::CheckEquivalentExceptionSpec( | 
|  | 469 | const FunctionProtoType *Old, SourceLocation OldLoc, | 
|  | 470 | const FunctionProtoType *New, SourceLocation NewLoc) { | 
| Richard Smith | 13b40bc | 2016-11-30 00:13:55 +0000 | [diff] [blame] | 471 | if (!getLangOpts().CXXExceptions) | 
|  | 472 | return false; | 
|  | 473 |  | 
| Francois Pichet | 13b4e68 | 2011-03-19 23:05:18 +0000 | [diff] [blame] | 474 | unsigned DiagID = diag::err_mismatched_exception_spec; | 
| Reid Kleckner | 39aa895 | 2019-08-27 17:52:03 +0000 | [diff] [blame] | 475 | if (getLangOpts().MSVCCompat) | 
| Richard Smith | 1b98ccc | 2014-07-19 01:39:17 +0000 | [diff] [blame] | 476 | DiagID = diag::ext_mismatched_exception_spec; | 
| Richard Smith | 13b40bc | 2016-11-30 00:13:55 +0000 | [diff] [blame] | 477 | bool Result = CheckEquivalentExceptionSpecImpl( | 
|  | 478 | *this, PDiag(DiagID), PDiag(diag::note_previous_declaration), | 
|  | 479 | Old, OldLoc, New, NewLoc); | 
| Hans Wennborg | 39a509a | 2014-02-05 02:37:58 +0000 | [diff] [blame] | 480 |  | 
|  | 481 | // In Microsoft mode, mismatching exception specifications just cause a warning. | 
| Reid Kleckner | 39aa895 | 2019-08-27 17:52:03 +0000 | [diff] [blame] | 482 | if (getLangOpts().MSVCCompat) | 
| Hans Wennborg | 39a509a | 2014-02-05 02:37:58 +0000 | [diff] [blame] | 483 | return false; | 
|  | 484 | return Result; | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 485 | } | 
|  | 486 |  | 
| Sebastian Redl | fa453cf | 2011-03-12 11:50:43 +0000 | [diff] [blame] | 487 | /// CheckEquivalentExceptionSpec - Check if the two types have compatible | 
|  | 488 | /// exception specifications. See C++ [except.spec]p3. | 
| Richard Smith | 66f3ac9 | 2012-10-20 08:26:51 +0000 | [diff] [blame] | 489 | /// | 
|  | 490 | /// \return \c false if the exception specifications match, \c true if there is | 
|  | 491 | /// a problem. If \c true is returned, either a diagnostic has already been | 
|  | 492 | /// produced or \c *MissingExceptionSpecification is set to \c true. | 
| Richard Smith | 13b40bc | 2016-11-30 00:13:55 +0000 | [diff] [blame] | 493 | static bool CheckEquivalentExceptionSpecImpl( | 
|  | 494 | Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID, | 
|  | 495 | const FunctionProtoType *Old, SourceLocation OldLoc, | 
|  | 496 | const FunctionProtoType *New, SourceLocation NewLoc, | 
|  | 497 | bool *MissingExceptionSpecification, | 
|  | 498 | bool *MissingEmptyExceptionSpecification, | 
|  | 499 | bool AllowNoexceptAllMatchWithNoSpec, bool IsOperatorNew) { | 
| Douglas Gregor | d6bc5e6 | 2010-03-24 07:14:45 +0000 | [diff] [blame] | 500 | if (MissingExceptionSpecification) | 
|  | 501 | *MissingExceptionSpecification = false; | 
|  | 502 |  | 
| Douglas Gregor | f40863c | 2010-02-12 07:32:17 +0000 | [diff] [blame] | 503 | if (MissingEmptyExceptionSpecification) | 
|  | 504 | *MissingEmptyExceptionSpecification = false; | 
|  | 505 |  | 
| Richard Smith | 13b40bc | 2016-11-30 00:13:55 +0000 | [diff] [blame] | 506 | Old = S.ResolveExceptionSpec(NewLoc, Old); | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 507 | if (!Old) | 
|  | 508 | return false; | 
| Richard Smith | 13b40bc | 2016-11-30 00:13:55 +0000 | [diff] [blame] | 509 | New = S.ResolveExceptionSpec(NewLoc, New); | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 510 | if (!New) | 
|  | 511 | return false; | 
|  | 512 |  | 
| Sebastian Redl | fa453cf | 2011-03-12 11:50:43 +0000 | [diff] [blame] | 513 | // C++0x [except.spec]p3: Two exception-specifications are compatible if: | 
|  | 514 | //   - both are non-throwing, regardless of their form, | 
|  | 515 | //   - both have the form noexcept(constant-expression) and the constant- | 
|  | 516 | //     expressions are equivalent, | 
| Sebastian Redl | fa453cf | 2011-03-12 11:50:43 +0000 | [diff] [blame] | 517 | //   - both are dynamic-exception-specifications that have the same set of | 
|  | 518 | //     adjusted types. | 
|  | 519 | // | 
| Eric Christopher | e6b7cf4 | 2015-07-10 18:25:52 +0000 | [diff] [blame] | 520 | // C++0x [except.spec]p12: An exception-specification is non-throwing if it is | 
| Sebastian Redl | fa453cf | 2011-03-12 11:50:43 +0000 | [diff] [blame] | 521 | //   of the form throw(), noexcept, or noexcept(constant-expression) where the | 
|  | 522 | //   constant-expression yields true. | 
|  | 523 | // | 
| Sebastian Redl | fa453cf | 2011-03-12 11:50:43 +0000 | [diff] [blame] | 524 | // C++0x [except.spec]p4: If any declaration of a function has an exception- | 
|  | 525 | //   specifier that is not a noexcept-specification allowing all exceptions, | 
|  | 526 | //   all declarations [...] of that function shall have a compatible | 
|  | 527 | //   exception-specification. | 
|  | 528 | // | 
|  | 529 | // That last point basically means that noexcept(false) matches no spec. | 
|  | 530 | // It's considered when AllowNoexceptAllMatchWithNoSpec is true. | 
|  | 531 |  | 
|  | 532 | ExceptionSpecificationType OldEST = Old->getExceptionSpecType(); | 
|  | 533 | ExceptionSpecificationType NewEST = New->getExceptionSpecType(); | 
|  | 534 |  | 
| Richard Smith | d3b5c908 | 2012-07-27 04:22:15 +0000 | [diff] [blame] | 535 | assert(!isUnresolvedExceptionSpec(OldEST) && | 
|  | 536 | !isUnresolvedExceptionSpec(NewEST) && | 
| Richard Smith | 938f40b | 2011-06-11 17:19:42 +0000 | [diff] [blame] | 537 | "Shouldn't see unknown exception specifications here"); | 
|  | 538 |  | 
| Richard Smith | eaf11ad | 2018-05-03 03:58:32 +0000 | [diff] [blame] | 539 | CanThrowResult OldCanThrow = Old->canThrow(); | 
|  | 540 | CanThrowResult NewCanThrow = New->canThrow(); | 
| Sebastian Redl | fa453cf | 2011-03-12 11:50:43 +0000 | [diff] [blame] | 541 |  | 
|  | 542 | // Any non-throwing specifications are compatible. | 
| Richard Smith | eaf11ad | 2018-05-03 03:58:32 +0000 | [diff] [blame] | 543 | if (OldCanThrow == CT_Cannot && NewCanThrow == CT_Cannot) | 
| Sebastian Redl | fa453cf | 2011-03-12 11:50:43 +0000 | [diff] [blame] | 544 | return false; | 
|  | 545 |  | 
| Richard Smith | eaf11ad | 2018-05-03 03:58:32 +0000 | [diff] [blame] | 546 | // Any throws-anything specifications are usually compatible. | 
|  | 547 | if (OldCanThrow == CT_Can && OldEST != EST_Dynamic && | 
|  | 548 | NewCanThrow == CT_Can && NewEST != EST_Dynamic) { | 
|  | 549 | // The exception is that the absence of an exception specification only | 
|  | 550 | // matches noexcept(false) for functions, as described above. | 
|  | 551 | if (!AllowNoexceptAllMatchWithNoSpec && | 
|  | 552 | ((OldEST == EST_None && NewEST == EST_NoexceptFalse) || | 
|  | 553 | (OldEST == EST_NoexceptFalse && NewEST == EST_None))) { | 
|  | 554 | // This is the disallowed case. | 
|  | 555 | } else { | 
|  | 556 | return false; | 
|  | 557 | } | 
|  | 558 | } | 
|  | 559 |  | 
| Richard Smith | b64764a | 2018-07-12 21:11:25 +0000 | [diff] [blame] | 560 | // C++14 [except.spec]p3: | 
|  | 561 | //   Two exception-specifications are compatible if [...] both have the form | 
|  | 562 | //   noexcept(constant-expression) and the constant-expressions are equivalent | 
|  | 563 | if (OldEST == EST_DependentNoexcept && NewEST == EST_DependentNoexcept) { | 
|  | 564 | llvm::FoldingSetNodeID OldFSN, NewFSN; | 
|  | 565 | Old->getNoexceptExpr()->Profile(OldFSN, S.Context, true); | 
|  | 566 | New->getNoexceptExpr()->Profile(NewFSN, S.Context, true); | 
|  | 567 | if (OldFSN == NewFSN) | 
|  | 568 | return false; | 
|  | 569 | } | 
| Richard Smith | eaf11ad | 2018-05-03 03:58:32 +0000 | [diff] [blame] | 570 |  | 
|  | 571 | // Dynamic exception specifications with the same set of adjusted types | 
|  | 572 | // are compatible. | 
|  | 573 | if (OldEST == EST_Dynamic && NewEST == EST_Dynamic) { | 
|  | 574 | bool Success = true; | 
|  | 575 | // Both have a dynamic exception spec. Collect the first set, then compare | 
|  | 576 | // to the second. | 
|  | 577 | llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes; | 
|  | 578 | for (const auto &I : Old->exceptions()) | 
|  | 579 | OldTypes.insert(S.Context.getCanonicalType(I).getUnqualifiedType()); | 
|  | 580 |  | 
|  | 581 | for (const auto &I : New->exceptions()) { | 
|  | 582 | CanQualType TypePtr = S.Context.getCanonicalType(I).getUnqualifiedType(); | 
|  | 583 | if (OldTypes.count(TypePtr)) | 
|  | 584 | NewTypes.insert(TypePtr); | 
|  | 585 | else { | 
|  | 586 | Success = false; | 
|  | 587 | break; | 
|  | 588 | } | 
|  | 589 | } | 
|  | 590 |  | 
|  | 591 | if (Success && OldTypes.size() == NewTypes.size()) | 
|  | 592 | return false; | 
|  | 593 | } | 
|  | 594 |  | 
| Sebastian Redl | cb5dd00 | 2011-03-15 19:52:30 +0000 | [diff] [blame] | 595 | // As a special compatibility feature, under C++0x we accept no spec and | 
|  | 596 | // throw(std::bad_alloc) as equivalent for operator new and operator new[]. | 
|  | 597 | // This is because the implicit declaration changed, but old code would break. | 
| Richard Smith | 13b40bc | 2016-11-30 00:13:55 +0000 | [diff] [blame] | 598 | if (S.getLangOpts().CPlusPlus11 && IsOperatorNew) { | 
| Craig Topper | c3ec149 | 2014-05-26 06:22:03 +0000 | [diff] [blame] | 599 | const FunctionProtoType *WithExceptions = nullptr; | 
| Sebastian Redl | cb5dd00 | 2011-03-15 19:52:30 +0000 | [diff] [blame] | 600 | if (OldEST == EST_None && NewEST == EST_Dynamic) | 
|  | 601 | WithExceptions = New; | 
|  | 602 | else if (OldEST == EST_Dynamic && NewEST == EST_None) | 
|  | 603 | WithExceptions = Old; | 
|  | 604 | if (WithExceptions && WithExceptions->getNumExceptions() == 1) { | 
|  | 605 | // One has no spec, the other throw(something). If that something is | 
|  | 606 | // std::bad_alloc, all conditions are met. | 
|  | 607 | QualType Exception = *WithExceptions->exception_begin(); | 
|  | 608 | if (CXXRecordDecl *ExRecord = Exception->getAsCXXRecordDecl()) { | 
|  | 609 | IdentifierInfo* Name = ExRecord->getIdentifier(); | 
|  | 610 | if (Name && Name->getName() == "bad_alloc") { | 
|  | 611 | // It's called bad_alloc, but is it in std? | 
| Richard Trieu | c771d5d | 2014-05-28 02:16:01 +0000 | [diff] [blame] | 612 | if (ExRecord->isInStdNamespace()) { | 
|  | 613 | return false; | 
| Sebastian Redl | cb5dd00 | 2011-03-15 19:52:30 +0000 | [diff] [blame] | 614 | } | 
|  | 615 | } | 
|  | 616 | } | 
|  | 617 | } | 
|  | 618 | } | 
|  | 619 |  | 
| Richard Smith | eaf11ad | 2018-05-03 03:58:32 +0000 | [diff] [blame] | 620 | // If the caller wants to handle the case that the new function is | 
|  | 621 | // incompatible due to a missing exception specification, let it. | 
|  | 622 | if (MissingExceptionSpecification && OldEST != EST_None && | 
|  | 623 | NewEST == EST_None) { | 
|  | 624 | // The old type has an exception specification of some sort, but | 
|  | 625 | // the new type does not. | 
|  | 626 | *MissingExceptionSpecification = true; | 
| Douglas Gregor | d6bc5e6 | 2010-03-24 07:14:45 +0000 | [diff] [blame] | 627 |  | 
| Richard Smith | eaf11ad | 2018-05-03 03:58:32 +0000 | [diff] [blame] | 628 | if (MissingEmptyExceptionSpecification && OldCanThrow == CT_Cannot) { | 
|  | 629 | // The old type has a throw() or noexcept(true) exception specification | 
|  | 630 | // and the new type has no exception specification, and the caller asked | 
|  | 631 | // to handle this itself. | 
|  | 632 | *MissingEmptyExceptionSpecification = true; | 
| Douglas Gregor | f40863c | 2010-02-12 07:32:17 +0000 | [diff] [blame] | 633 | } | 
|  | 634 |  | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 635 | return true; | 
|  | 636 | } | 
|  | 637 |  | 
| Richard Smith | 13b40bc | 2016-11-30 00:13:55 +0000 | [diff] [blame] | 638 | S.Diag(NewLoc, DiagID); | 
| David Majnemer | 7da2302 | 2015-02-19 07:28:55 +0000 | [diff] [blame] | 639 | if (NoteID.getDiagID() != 0 && OldLoc.isValid()) | 
| Richard Smith | 13b40bc | 2016-11-30 00:13:55 +0000 | [diff] [blame] | 640 | S.Diag(OldLoc, NoteID); | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 641 | return true; | 
|  | 642 | } | 
|  | 643 |  | 
| Richard Smith | 13b40bc | 2016-11-30 00:13:55 +0000 | [diff] [blame] | 644 | bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, | 
|  | 645 | const PartialDiagnostic &NoteID, | 
|  | 646 | const FunctionProtoType *Old, | 
|  | 647 | SourceLocation OldLoc, | 
|  | 648 | const FunctionProtoType *New, | 
|  | 649 | SourceLocation NewLoc) { | 
|  | 650 | if (!getLangOpts().CXXExceptions) | 
|  | 651 | return false; | 
|  | 652 | return CheckEquivalentExceptionSpecImpl(*this, DiagID, NoteID, Old, OldLoc, | 
|  | 653 | New, NewLoc); | 
|  | 654 | } | 
|  | 655 |  | 
| Richard Smith | 56ae0a6 | 2018-01-13 05:05:45 +0000 | [diff] [blame] | 656 | bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) { | 
|  | 657 | // [except.handle]p3: | 
|  | 658 | //   A handler is a match for an exception object of type E if: | 
|  | 659 |  | 
|  | 660 | // HandlerType must be ExceptionType or derived from it, or pointer or | 
|  | 661 | // reference to such types. | 
|  | 662 | const ReferenceType *RefTy = HandlerType->getAs<ReferenceType>(); | 
|  | 663 | if (RefTy) | 
|  | 664 | HandlerType = RefTy->getPointeeType(); | 
|  | 665 |  | 
|  | 666 | //   -- the handler is of type cv T or cv T& and E and T are the same type | 
|  | 667 | if (Context.hasSameUnqualifiedType(ExceptionType, HandlerType)) | 
|  | 668 | return true; | 
|  | 669 |  | 
|  | 670 | // FIXME: ObjC pointer types? | 
|  | 671 | if (HandlerType->isPointerType() || HandlerType->isMemberPointerType()) { | 
|  | 672 | if (RefTy && (!HandlerType.isConstQualified() || | 
|  | 673 | HandlerType.isVolatileQualified())) | 
|  | 674 | return false; | 
|  | 675 |  | 
|  | 676 | // -- the handler is of type cv T or const T& where T is a pointer or | 
|  | 677 | //    pointer to member type and E is std::nullptr_t | 
|  | 678 | if (ExceptionType->isNullPtrType()) | 
|  | 679 | return true; | 
|  | 680 |  | 
|  | 681 | // -- the handler is of type cv T or const T& where T is a pointer or | 
|  | 682 | //    pointer to member type and E is a pointer or pointer to member type | 
|  | 683 | //    that can be converted to T by one or more of | 
|  | 684 | //    -- a qualification conversion | 
|  | 685 | //    -- a function pointer conversion | 
|  | 686 | bool LifetimeConv; | 
|  | 687 | QualType Result; | 
|  | 688 | // FIXME: Should we treat the exception as catchable if a lifetime | 
|  | 689 | // conversion is required? | 
|  | 690 | if (IsQualificationConversion(ExceptionType, HandlerType, false, | 
|  | 691 | LifetimeConv) || | 
|  | 692 | IsFunctionConversion(ExceptionType, HandlerType, Result)) | 
|  | 693 | return true; | 
|  | 694 |  | 
|  | 695 | //    -- a standard pointer conversion [...] | 
|  | 696 | if (!ExceptionType->isPointerType() || !HandlerType->isPointerType()) | 
|  | 697 | return false; | 
|  | 698 |  | 
|  | 699 | // Handle the "qualification conversion" portion. | 
|  | 700 | Qualifiers EQuals, HQuals; | 
|  | 701 | ExceptionType = Context.getUnqualifiedArrayType( | 
|  | 702 | ExceptionType->getPointeeType(), EQuals); | 
|  | 703 | HandlerType = Context.getUnqualifiedArrayType( | 
|  | 704 | HandlerType->getPointeeType(), HQuals); | 
|  | 705 | if (!HQuals.compatiblyIncludes(EQuals)) | 
|  | 706 | return false; | 
|  | 707 |  | 
|  | 708 | if (HandlerType->isVoidType() && ExceptionType->isObjectType()) | 
|  | 709 | return true; | 
|  | 710 |  | 
|  | 711 | // The only remaining case is a derived-to-base conversion. | 
|  | 712 | } | 
|  | 713 |  | 
|  | 714 | //   -- the handler is of type cg T or cv T& and T is an unambiguous public | 
|  | 715 | //      base class of E | 
|  | 716 | if (!ExceptionType->isRecordType() || !HandlerType->isRecordType()) | 
|  | 717 | return false; | 
|  | 718 | CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, | 
|  | 719 | /*DetectVirtual=*/false); | 
|  | 720 | if (!IsDerivedFrom(SourceLocation(), ExceptionType, HandlerType, Paths) || | 
|  | 721 | Paths.isAmbiguous(Context.getCanonicalType(HandlerType))) | 
|  | 722 | return false; | 
|  | 723 |  | 
|  | 724 | // Do this check from a context without privileges. | 
|  | 725 | switch (CheckBaseClassAccess(SourceLocation(), HandlerType, ExceptionType, | 
|  | 726 | Paths.front(), | 
|  | 727 | /*Diagnostic*/ 0, | 
|  | 728 | /*ForceCheck*/ true, | 
|  | 729 | /*ForceUnprivileged*/ true)) { | 
|  | 730 | case AR_accessible: return true; | 
|  | 731 | case AR_inaccessible: return false; | 
|  | 732 | case AR_dependent: | 
|  | 733 | llvm_unreachable("access check dependent for unprivileged context"); | 
|  | 734 | case AR_delayed: | 
|  | 735 | llvm_unreachable("access check delayed in non-declaration"); | 
|  | 736 | } | 
|  | 737 | llvm_unreachable("unexpected access check result"); | 
|  | 738 | } | 
|  | 739 |  | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 740 | /// CheckExceptionSpecSubset - Check whether the second function type's | 
|  | 741 | /// exception specification is a subset (or equivalent) of the first function | 
|  | 742 | /// type. This is used by override and pointer assignment checks. | 
| Richard Smith | 1be59c5 | 2016-10-22 01:32:19 +0000 | [diff] [blame] | 743 | bool Sema::CheckExceptionSpecSubset(const PartialDiagnostic &DiagID, | 
|  | 744 | const PartialDiagnostic &NestedDiagID, | 
|  | 745 | const PartialDiagnostic &NoteID, | 
| Erich Keane | 81ef625 | 2019-06-03 18:36:26 +0000 | [diff] [blame] | 746 | const PartialDiagnostic &NoThrowDiagID, | 
| Richard Smith | 1be59c5 | 2016-10-22 01:32:19 +0000 | [diff] [blame] | 747 | const FunctionProtoType *Superset, | 
|  | 748 | SourceLocation SuperLoc, | 
|  | 749 | const FunctionProtoType *Subset, | 
|  | 750 | SourceLocation SubLoc) { | 
| John McCall | f9c9409 | 2010-05-28 08:37:35 +0000 | [diff] [blame] | 751 |  | 
|  | 752 | // Just auto-succeed under -fno-exceptions. | 
| David Blaikie | bbafb8a | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 753 | if (!getLangOpts().CXXExceptions) | 
| John McCall | f9c9409 | 2010-05-28 08:37:35 +0000 | [diff] [blame] | 754 | return false; | 
|  | 755 |  | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 756 | // FIXME: As usual, we could be more specific in our error messages, but | 
|  | 757 | // that better waits until we've got types with source locations. | 
|  | 758 |  | 
|  | 759 | if (!SubLoc.isValid()) | 
|  | 760 | SubLoc = SuperLoc; | 
|  | 761 |  | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 762 | // Resolve the exception specifications, if needed. | 
|  | 763 | Superset = ResolveExceptionSpec(SuperLoc, Superset); | 
|  | 764 | if (!Superset) | 
|  | 765 | return false; | 
|  | 766 | Subset = ResolveExceptionSpec(SubLoc, Subset); | 
|  | 767 | if (!Subset) | 
|  | 768 | return false; | 
|  | 769 |  | 
| Sebastian Redl | fa453cf | 2011-03-12 11:50:43 +0000 | [diff] [blame] | 770 | ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType(); | 
| Richard Smith | eaf11ad | 2018-05-03 03:58:32 +0000 | [diff] [blame] | 771 | ExceptionSpecificationType SubEST = Subset->getExceptionSpecType(); | 
|  | 772 | assert(!isUnresolvedExceptionSpec(SuperEST) && | 
|  | 773 | !isUnresolvedExceptionSpec(SubEST) && | 
|  | 774 | "Shouldn't see unknown exception specifications here"); | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 775 |  | 
| Sebastian Redl | fa453cf | 2011-03-12 11:50:43 +0000 | [diff] [blame] | 776 | // If there are dependent noexcept specs, assume everything is fine. Unlike | 
|  | 777 | // with the equivalency check, this is safe in this case, because we don't | 
|  | 778 | // want to merge declarations. Checks after instantiation will catch any | 
|  | 779 | // omissions we make here. | 
| Richard Smith | eaf11ad | 2018-05-03 03:58:32 +0000 | [diff] [blame] | 780 | if (SuperEST == EST_DependentNoexcept || SubEST == EST_DependentNoexcept) | 
| Sebastian Redl | fa453cf | 2011-03-12 11:50:43 +0000 | [diff] [blame] | 781 | return false; | 
|  | 782 |  | 
| Richard Smith | eaf11ad | 2018-05-03 03:58:32 +0000 | [diff] [blame] | 783 | CanThrowResult SuperCanThrow = Superset->canThrow(); | 
|  | 784 | CanThrowResult SubCanThrow = Subset->canThrow(); | 
|  | 785 |  | 
|  | 786 | // If the superset contains everything or the subset contains nothing, we're | 
|  | 787 | // done. | 
|  | 788 | if ((SuperCanThrow == CT_Can && SuperEST != EST_Dynamic) || | 
|  | 789 | SubCanThrow == CT_Cannot) | 
| Richard Smith | 1be59c5 | 2016-10-22 01:32:19 +0000 | [diff] [blame] | 790 | return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc, | 
|  | 791 | Subset, SubLoc); | 
| Sebastian Redl | fa453cf | 2011-03-12 11:50:43 +0000 | [diff] [blame] | 792 |  | 
| Erich Keane | 81ef625 | 2019-06-03 18:36:26 +0000 | [diff] [blame] | 793 | // Allow __declspec(nothrow) to be missing on redeclaration as an extension in | 
|  | 794 | // some cases. | 
|  | 795 | if (NoThrowDiagID.getDiagID() != 0 && SubCanThrow == CT_Can && | 
|  | 796 | SuperCanThrow == CT_Cannot && SuperEST == EST_NoThrow) { | 
|  | 797 | Diag(SubLoc, NoThrowDiagID); | 
|  | 798 | if (NoteID.getDiagID() != 0) | 
|  | 799 | Diag(SuperLoc, NoteID); | 
|  | 800 | return true; | 
|  | 801 | } | 
|  | 802 |  | 
| Richard Smith | eaf11ad | 2018-05-03 03:58:32 +0000 | [diff] [blame] | 803 | // If the subset contains everything or the superset contains nothing, we've | 
|  | 804 | // failed. | 
|  | 805 | if ((SubCanThrow == CT_Can && SubEST != EST_Dynamic) || | 
|  | 806 | SuperCanThrow == CT_Cannot) { | 
| Sebastian Redl | fa453cf | 2011-03-12 11:50:43 +0000 | [diff] [blame] | 807 | Diag(SubLoc, DiagID); | 
|  | 808 | if (NoteID.getDiagID() != 0) | 
|  | 809 | Diag(SuperLoc, NoteID); | 
|  | 810 | return true; | 
|  | 811 | } | 
|  | 812 |  | 
|  | 813 | assert(SuperEST == EST_Dynamic && SubEST == EST_Dynamic && | 
|  | 814 | "Exception spec subset: non-dynamic case slipped through."); | 
|  | 815 |  | 
|  | 816 | // Neither contains everything or nothing. Do a proper comparison. | 
| Richard Smith | 56ae0a6 | 2018-01-13 05:05:45 +0000 | [diff] [blame] | 817 | for (QualType SubI : Subset->exceptions()) { | 
|  | 818 | if (const ReferenceType *RefTy = SubI->getAs<ReferenceType>()) | 
|  | 819 | SubI = RefTy->getPointeeType(); | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 820 |  | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 821 | // Make sure it's in the superset. | 
| Richard Smith | 56ae0a6 | 2018-01-13 05:05:45 +0000 | [diff] [blame] | 822 | bool Contained = false; | 
|  | 823 | for (QualType SuperI : Superset->exceptions()) { | 
|  | 824 | // [except.spec]p5: | 
|  | 825 | //   the target entity shall allow at least the exceptions allowed by the | 
|  | 826 | //   source | 
|  | 827 | // | 
|  | 828 | // We interpret this as meaning that a handler for some target type would | 
|  | 829 | // catch an exception of each source type. | 
|  | 830 | if (handlerCanCatch(SuperI, SubI)) { | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 831 | Contained = true; | 
|  | 832 | break; | 
|  | 833 | } | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 834 | } | 
|  | 835 | if (!Contained) { | 
|  | 836 | Diag(SubLoc, DiagID); | 
| Sebastian Redl | a44822f | 2009-10-14 16:09:29 +0000 | [diff] [blame] | 837 | if (NoteID.getDiagID() != 0) | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 838 | Diag(SuperLoc, NoteID); | 
|  | 839 | return true; | 
|  | 840 | } | 
|  | 841 | } | 
|  | 842 | // We've run half the gauntlet. | 
| Richard Smith | 1be59c5 | 2016-10-22 01:32:19 +0000 | [diff] [blame] | 843 | return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc, | 
|  | 844 | Subset, SubLoc); | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 845 | } | 
|  | 846 |  | 
| Richard Smith | 1be59c5 | 2016-10-22 01:32:19 +0000 | [diff] [blame] | 847 | static bool | 
|  | 848 | CheckSpecForTypesEquivalent(Sema &S, const PartialDiagnostic &DiagID, | 
|  | 849 | const PartialDiagnostic &NoteID, QualType Target, | 
|  | 850 | SourceLocation TargetLoc, QualType Source, | 
|  | 851 | SourceLocation SourceLoc) { | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 852 | const FunctionProtoType *TFunc = GetUnderlyingFunction(Target); | 
|  | 853 | if (!TFunc) | 
|  | 854 | return false; | 
|  | 855 | const FunctionProtoType *SFunc = GetUnderlyingFunction(Source); | 
|  | 856 | if (!SFunc) | 
|  | 857 | return false; | 
|  | 858 |  | 
|  | 859 | return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc, | 
|  | 860 | SFunc, SourceLoc); | 
|  | 861 | } | 
|  | 862 |  | 
|  | 863 | /// CheckParamExceptionSpec - Check if the parameter and return types of the | 
|  | 864 | /// two functions have equivalent exception specs. This is part of the | 
|  | 865 | /// assignment and override compatibility check. We do not check the parameters | 
|  | 866 | /// of parameter function pointers recursively, as no sane programmer would | 
|  | 867 | /// even be able to write such a function type. | 
| Richard Smith | 1be59c5 | 2016-10-22 01:32:19 +0000 | [diff] [blame] | 868 | bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &DiagID, | 
|  | 869 | const PartialDiagnostic &NoteID, | 
| Richard Smith | 2e32155 | 2014-11-12 02:00:47 +0000 | [diff] [blame] | 870 | const FunctionProtoType *Target, | 
|  | 871 | SourceLocation TargetLoc, | 
|  | 872 | const FunctionProtoType *Source, | 
|  | 873 | SourceLocation SourceLoc) { | 
| Richard Smith | 1be59c5 | 2016-10-22 01:32:19 +0000 | [diff] [blame] | 874 | auto RetDiag = DiagID; | 
|  | 875 | RetDiag << 0; | 
| Alp Toker | 314cc81 | 2014-01-25 16:55:45 +0000 | [diff] [blame] | 876 | if (CheckSpecForTypesEquivalent( | 
| Richard Smith | 1be59c5 | 2016-10-22 01:32:19 +0000 | [diff] [blame] | 877 | *this, RetDiag, PDiag(), | 
| Alp Toker | 314cc81 | 2014-01-25 16:55:45 +0000 | [diff] [blame] | 878 | Target->getReturnType(), TargetLoc, Source->getReturnType(), | 
|  | 879 | SourceLoc)) | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 880 | return true; | 
|  | 881 |  | 
| Sebastian Redl | a44822f | 2009-10-14 16:09:29 +0000 | [diff] [blame] | 882 | // We shouldn't even be testing this unless the arguments are otherwise | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 883 | // compatible. | 
| Alp Toker | 9cacbab | 2014-01-20 20:26:09 +0000 | [diff] [blame] | 884 | assert(Target->getNumParams() == Source->getNumParams() && | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 885 | "Functions have different argument counts."); | 
| Alp Toker | 9cacbab | 2014-01-20 20:26:09 +0000 | [diff] [blame] | 886 | for (unsigned i = 0, E = Target->getNumParams(); i != E; ++i) { | 
| Richard Smith | 1be59c5 | 2016-10-22 01:32:19 +0000 | [diff] [blame] | 887 | auto ParamDiag = DiagID; | 
|  | 888 | ParamDiag << 1; | 
| Alp Toker | 9cacbab | 2014-01-20 20:26:09 +0000 | [diff] [blame] | 889 | if (CheckSpecForTypesEquivalent( | 
| Richard Smith | 1be59c5 | 2016-10-22 01:32:19 +0000 | [diff] [blame] | 890 | *this, ParamDiag, PDiag(), | 
| Alp Toker | 9cacbab | 2014-01-20 20:26:09 +0000 | [diff] [blame] | 891 | Target->getParamType(i), TargetLoc, Source->getParamType(i), | 
|  | 892 | SourceLoc)) | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 893 | return true; | 
|  | 894 | } | 
|  | 895 | return false; | 
|  | 896 | } | 
|  | 897 |  | 
| Richard Smith | 2e32155 | 2014-11-12 02:00:47 +0000 | [diff] [blame] | 898 | bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) { | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 899 | // First we check for applicability. | 
|  | 900 | // Target type must be a function, function pointer or function reference. | 
|  | 901 | const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType); | 
| Richard Smith | 2e32155 | 2014-11-12 02:00:47 +0000 | [diff] [blame] | 902 | if (!ToFunc || ToFunc->hasDependentExceptionSpec()) | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 903 | return false; | 
|  | 904 |  | 
|  | 905 | // SourceType must be a function or function pointer. | 
|  | 906 | const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType()); | 
| Richard Smith | 2e32155 | 2014-11-12 02:00:47 +0000 | [diff] [blame] | 907 | if (!FromFunc || FromFunc->hasDependentExceptionSpec()) | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 908 | return false; | 
|  | 909 |  | 
| Richard Smith | 1be59c5 | 2016-10-22 01:32:19 +0000 | [diff] [blame] | 910 | unsigned DiagID = diag::err_incompatible_exception_specs; | 
|  | 911 | unsigned NestedDiagID = diag::err_deep_exception_specs_differ; | 
|  | 912 | // This is not an error in C++17 onwards, unless the noexceptness doesn't | 
|  | 913 | // match, but in that case we have a full-on type mismatch, not just a | 
|  | 914 | // type sugar mismatch. | 
| Aaron Ballman | c351fba | 2017-12-04 20:27:34 +0000 | [diff] [blame] | 915 | if (getLangOpts().CPlusPlus17) { | 
| Richard Smith | 1be59c5 | 2016-10-22 01:32:19 +0000 | [diff] [blame] | 916 | DiagID = diag::warn_incompatible_exception_specs; | 
|  | 917 | NestedDiagID = diag::warn_deep_exception_specs_differ; | 
|  | 918 | } | 
|  | 919 |  | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 920 | // Now we've got the correct types on both sides, check their compatibility. | 
|  | 921 | // This means that the source of the conversion can only throw a subset of | 
|  | 922 | // the exceptions of the target, and any exception specs on arguments or | 
|  | 923 | // return types must be equivalent. | 
| Richard Smith | 2e32155 | 2014-11-12 02:00:47 +0000 | [diff] [blame] | 924 | // | 
|  | 925 | // FIXME: If there is a nested dependent exception specification, we should | 
|  | 926 | // not be checking it here. This is fine: | 
|  | 927 | //   template<typename T> void f() { | 
|  | 928 | //     void (*p)(void (*) throw(T)); | 
|  | 929 | //     void (*q)(void (*) throw(int)) = p; | 
|  | 930 | //   } | 
|  | 931 | // ... because it might be instantiated with T=int. | 
| Erich Keane | 81ef625 | 2019-06-03 18:36:26 +0000 | [diff] [blame] | 932 | return CheckExceptionSpecSubset( | 
|  | 933 | PDiag(DiagID), PDiag(NestedDiagID), PDiag(), PDiag(), ToFunc, | 
|  | 934 | From->getSourceRange().getBegin(), FromFunc, SourceLocation()) && | 
| Aaron Ballman | c351fba | 2017-12-04 20:27:34 +0000 | [diff] [blame] | 935 | !getLangOpts().CPlusPlus17; | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 936 | } | 
|  | 937 |  | 
|  | 938 | bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, | 
|  | 939 | const CXXMethodDecl *Old) { | 
| Richard Smith | 88f4549 | 2014-11-22 03:09:05 +0000 | [diff] [blame] | 940 | // If the new exception specification hasn't been parsed yet, skip the check. | 
|  | 941 | // We'll get called again once it's been parsed. | 
|  | 942 | if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() == | 
|  | 943 | EST_Unparsed) | 
|  | 944 | return false; | 
| Richard Smith | 5159bbad | 2018-09-05 22:30:37 +0000 | [diff] [blame] | 945 |  | 
|  | 946 | // Don't check uninstantiated template destructors at all. We can only | 
|  | 947 | // synthesize correct specs after the template is instantiated. | 
|  | 948 | if (isa<CXXDestructorDecl>(New) && New->getParent()->isDependentType()) | 
|  | 949 | return false; | 
|  | 950 |  | 
|  | 951 | // If the old exception specification hasn't been parsed yet, or the new | 
|  | 952 | // exception specification can't be computed yet, remember that we need to | 
|  | 953 | // perform this check when we get to the end of the outermost | 
| Richard Smith | 88f4549 | 2014-11-22 03:09:05 +0000 | [diff] [blame] | 954 | // lexically-surrounding class. | 
| Richard Smith | 5159bbad | 2018-09-05 22:30:37 +0000 | [diff] [blame] | 955 | if (exceptionSpecNotKnownYet(Old) || exceptionSpecNotKnownYet(New)) { | 
|  | 956 | DelayedOverridingExceptionSpecChecks.push_back({New, Old}); | 
| Richard Smith | 0b3a462 | 2014-11-13 20:01:57 +0000 | [diff] [blame] | 957 | return false; | 
| Richard Smith | 88f4549 | 2014-11-22 03:09:05 +0000 | [diff] [blame] | 958 | } | 
| Richard Smith | 5159bbad | 2018-09-05 22:30:37 +0000 | [diff] [blame] | 959 |  | 
| Francois Pichet | a8032e9 | 2011-05-24 02:11:43 +0000 | [diff] [blame] | 960 | unsigned DiagID = diag::err_override_exception_spec; | 
| Reid Kleckner | 39aa895 | 2019-08-27 17:52:03 +0000 | [diff] [blame] | 961 | if (getLangOpts().MSVCCompat) | 
| Richard Smith | 1b98ccc | 2014-07-19 01:39:17 +0000 | [diff] [blame] | 962 | DiagID = diag::ext_override_exception_spec; | 
| Francois Pichet | a8032e9 | 2011-05-24 02:11:43 +0000 | [diff] [blame] | 963 | return CheckExceptionSpecSubset(PDiag(DiagID), | 
| Richard Smith | 1be59c5 | 2016-10-22 01:32:19 +0000 | [diff] [blame] | 964 | PDiag(diag::err_deep_exception_specs_differ), | 
| Douglas Gregor | 8933623 | 2010-03-29 23:34:08 +0000 | [diff] [blame] | 965 | PDiag(diag::note_overridden_virtual_function), | 
| Erich Keane | 81ef625 | 2019-06-03 18:36:26 +0000 | [diff] [blame] | 966 | PDiag(diag::ext_override_exception_spec), | 
| Simon Pilgrim | afb163f | 2019-10-21 18:28:31 +0000 | [diff] [blame] | 967 | Old->getType()->castAs<FunctionProtoType>(), | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 968 | Old->getLocation(), | 
| Simon Pilgrim | afb163f | 2019-10-21 18:28:31 +0000 | [diff] [blame] | 969 | New->getType()->castAs<FunctionProtoType>(), | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 970 | New->getLocation()); | 
|  | 971 | } | 
|  | 972 |  | 
| Benjamin Kramer | 642f173 | 2015-07-02 21:03:14 +0000 | [diff] [blame] | 973 | static CanThrowResult canSubExprsThrow(Sema &S, const Expr *E) { | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 974 | CanThrowResult R = CT_Cannot; | 
| Benjamin Kramer | 642f173 | 2015-07-02 21:03:14 +0000 | [diff] [blame] | 975 | for (const Stmt *SubStmt : E->children()) { | 
|  | 976 | R = mergeCanThrow(R, S.canThrow(cast<Expr>(SubStmt))); | 
|  | 977 | if (R == CT_Can) | 
|  | 978 | break; | 
|  | 979 | } | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 980 | return R; | 
|  | 981 | } | 
|  | 982 |  | 
| Eli Friedman | 0423b76 | 2013-06-25 01:24:22 +0000 | [diff] [blame] | 983 | static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) { | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 984 | // As an extension, we assume that __attribute__((nothrow)) functions don't | 
|  | 985 | // throw. | 
| Richard Smith | 3a8f13a | 2016-12-03 00:29:06 +0000 | [diff] [blame] | 986 | if (D && isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>()) | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 987 | return CT_Cannot; | 
|  | 988 |  | 
| Richard Smith | 3a8f13a | 2016-12-03 00:29:06 +0000 | [diff] [blame] | 989 | QualType T; | 
|  | 990 |  | 
|  | 991 | // In C++1z, just look at the function type of the callee. | 
| Aaron Ballman | c351fba | 2017-12-04 20:27:34 +0000 | [diff] [blame] | 992 | if (S.getLangOpts().CPlusPlus17 && isa<CallExpr>(E)) { | 
| Richard Smith | 3a8f13a | 2016-12-03 00:29:06 +0000 | [diff] [blame] | 993 | E = cast<CallExpr>(E)->getCallee(); | 
|  | 994 | T = E->getType(); | 
|  | 995 | if (T->isSpecificPlaceholderType(BuiltinType::BoundMember)) { | 
|  | 996 | // Sadly we don't preserve the actual type as part of the "bound member" | 
|  | 997 | // placeholder, so we need to reconstruct it. | 
|  | 998 | E = E->IgnoreParenImpCasts(); | 
|  | 999 |  | 
|  | 1000 | // Could be a call to a pointer-to-member or a plain member access. | 
|  | 1001 | if (auto *Op = dyn_cast<BinaryOperator>(E)) { | 
|  | 1002 | assert(Op->getOpcode() == BO_PtrMemD || Op->getOpcode() == BO_PtrMemI); | 
|  | 1003 | T = Op->getRHS()->getType() | 
|  | 1004 | ->castAs<MemberPointerType>()->getPointeeType(); | 
|  | 1005 | } else { | 
|  | 1006 | T = cast<MemberExpr>(E)->getMemberDecl()->getType(); | 
|  | 1007 | } | 
|  | 1008 | } | 
|  | 1009 | } else if (const ValueDecl *VD = dyn_cast_or_null<ValueDecl>(D)) | 
|  | 1010 | T = VD->getType(); | 
|  | 1011 | else | 
|  | 1012 | // If we have no clue what we're calling, assume the worst. | 
|  | 1013 | return CT_Can; | 
|  | 1014 |  | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1015 | const FunctionProtoType *FT; | 
|  | 1016 | if ((FT = T->getAs<FunctionProtoType>())) { | 
|  | 1017 | } else if (const PointerType *PT = T->getAs<PointerType>()) | 
|  | 1018 | FT = PT->getPointeeType()->getAs<FunctionProtoType>(); | 
|  | 1019 | else if (const ReferenceType *RT = T->getAs<ReferenceType>()) | 
|  | 1020 | FT = RT->getPointeeType()->getAs<FunctionProtoType>(); | 
|  | 1021 | else if (const MemberPointerType *MT = T->getAs<MemberPointerType>()) | 
|  | 1022 | FT = MT->getPointeeType()->getAs<FunctionProtoType>(); | 
|  | 1023 | else if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) | 
|  | 1024 | FT = BT->getPointeeType()->getAs<FunctionProtoType>(); | 
|  | 1025 |  | 
|  | 1026 | if (!FT) | 
|  | 1027 | return CT_Can; | 
|  | 1028 |  | 
| Stephen Kelly | f2ceec4 | 2018-08-09 21:08:08 +0000 | [diff] [blame] | 1029 | FT = S.ResolveExceptionSpec(E->getBeginLoc(), FT); | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1030 | if (!FT) | 
|  | 1031 | return CT_Can; | 
|  | 1032 |  | 
| Richard Smith | eaf11ad | 2018-05-03 03:58:32 +0000 | [diff] [blame] | 1033 | return FT->canThrow(); | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1034 | } | 
|  | 1035 |  | 
|  | 1036 | static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) { | 
|  | 1037 | if (DC->isTypeDependent()) | 
|  | 1038 | return CT_Dependent; | 
|  | 1039 |  | 
|  | 1040 | if (!DC->getTypeAsWritten()->isReferenceType()) | 
|  | 1041 | return CT_Cannot; | 
|  | 1042 |  | 
|  | 1043 | if (DC->getSubExpr()->isTypeDependent()) | 
|  | 1044 | return CT_Dependent; | 
|  | 1045 |  | 
|  | 1046 | return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot; | 
|  | 1047 | } | 
|  | 1048 |  | 
|  | 1049 | static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) { | 
|  | 1050 | if (DC->isTypeOperand()) | 
|  | 1051 | return CT_Cannot; | 
|  | 1052 |  | 
|  | 1053 | Expr *Op = DC->getExprOperand(); | 
|  | 1054 | if (Op->isTypeDependent()) | 
|  | 1055 | return CT_Dependent; | 
|  | 1056 |  | 
|  | 1057 | const RecordType *RT = Op->getType()->getAs<RecordType>(); | 
|  | 1058 | if (!RT) | 
|  | 1059 | return CT_Cannot; | 
|  | 1060 |  | 
|  | 1061 | if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic()) | 
|  | 1062 | return CT_Cannot; | 
|  | 1063 |  | 
|  | 1064 | if (Op->Classify(S.Context).isPRValue()) | 
|  | 1065 | return CT_Cannot; | 
|  | 1066 |  | 
|  | 1067 | return CT_Can; | 
|  | 1068 | } | 
|  | 1069 |  | 
|  | 1070 | CanThrowResult Sema::canThrow(const Expr *E) { | 
|  | 1071 | // C++ [expr.unary.noexcept]p3: | 
|  | 1072 | //   [Can throw] if in a potentially-evaluated context the expression would | 
|  | 1073 | //   contain: | 
|  | 1074 | switch (E->getStmtClass()) { | 
| Bill Wendling | 7c44da2 | 2018-10-31 03:48:47 +0000 | [diff] [blame] | 1075 | case Expr::ConstantExprClass: | 
|  | 1076 | return canThrow(cast<ConstantExpr>(E)->getSubExpr()); | 
|  | 1077 |  | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1078 | case Expr::CXXThrowExprClass: | 
|  | 1079 | //   - a potentially evaluated throw-expression | 
|  | 1080 | return CT_Can; | 
|  | 1081 |  | 
|  | 1082 | case Expr::CXXDynamicCastExprClass: { | 
|  | 1083 | //   - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v), | 
|  | 1084 | //     where T is a reference type, that requires a run-time check | 
|  | 1085 | CanThrowResult CT = canDynamicCastThrow(cast<CXXDynamicCastExpr>(E)); | 
|  | 1086 | if (CT == CT_Can) | 
|  | 1087 | return CT; | 
|  | 1088 | return mergeCanThrow(CT, canSubExprsThrow(*this, E)); | 
|  | 1089 | } | 
|  | 1090 |  | 
|  | 1091 | case Expr::CXXTypeidExprClass: | 
|  | 1092 | //   - a potentially evaluated typeid expression applied to a glvalue | 
|  | 1093 | //     expression whose type is a polymorphic class type | 
|  | 1094 | return canTypeidThrow(*this, cast<CXXTypeidExpr>(E)); | 
|  | 1095 |  | 
|  | 1096 | //   - a potentially evaluated call to a function, member function, function | 
|  | 1097 | //     pointer, or member function pointer that does not have a non-throwing | 
|  | 1098 | //     exception-specification | 
|  | 1099 | case Expr::CallExprClass: | 
|  | 1100 | case Expr::CXXMemberCallExprClass: | 
|  | 1101 | case Expr::CXXOperatorCallExprClass: | 
|  | 1102 | case Expr::UserDefinedLiteralClass: { | 
|  | 1103 | const CallExpr *CE = cast<CallExpr>(E); | 
|  | 1104 | CanThrowResult CT; | 
|  | 1105 | if (E->isTypeDependent()) | 
|  | 1106 | CT = CT_Dependent; | 
|  | 1107 | else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) | 
|  | 1108 | CT = CT_Cannot; | 
| Eli Friedman | 5a8738f | 2013-06-25 01:55:41 +0000 | [diff] [blame] | 1109 | else | 
| Richard Smith | 3a8f13a | 2016-12-03 00:29:06 +0000 | [diff] [blame] | 1110 | CT = canCalleeThrow(*this, E, CE->getCalleeDecl()); | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1111 | if (CT == CT_Can) | 
|  | 1112 | return CT; | 
|  | 1113 | return mergeCanThrow(CT, canSubExprsThrow(*this, E)); | 
|  | 1114 | } | 
|  | 1115 |  | 
|  | 1116 | case Expr::CXXConstructExprClass: | 
|  | 1117 | case Expr::CXXTemporaryObjectExprClass: { | 
|  | 1118 | CanThrowResult CT = canCalleeThrow(*this, E, | 
|  | 1119 | cast<CXXConstructExpr>(E)->getConstructor()); | 
|  | 1120 | if (CT == CT_Can) | 
|  | 1121 | return CT; | 
|  | 1122 | return mergeCanThrow(CT, canSubExprsThrow(*this, E)); | 
|  | 1123 | } | 
|  | 1124 |  | 
| Richard Smith | 5179eb7 | 2016-06-28 19:03:57 +0000 | [diff] [blame] | 1125 | case Expr::CXXInheritedCtorInitExprClass: | 
|  | 1126 | return canCalleeThrow(*this, E, | 
|  | 1127 | cast<CXXInheritedCtorInitExpr>(E)->getConstructor()); | 
|  | 1128 |  | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1129 | case Expr::LambdaExprClass: { | 
|  | 1130 | const LambdaExpr *Lambda = cast<LambdaExpr>(E); | 
|  | 1131 | CanThrowResult CT = CT_Cannot; | 
| James Y Knight | 53c7616 | 2015-07-17 18:21:37 +0000 | [diff] [blame] | 1132 | for (LambdaExpr::const_capture_init_iterator | 
|  | 1133 | Cap = Lambda->capture_init_begin(), | 
|  | 1134 | CapEnd = Lambda->capture_init_end(); | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1135 | Cap != CapEnd; ++Cap) | 
|  | 1136 | CT = mergeCanThrow(CT, canThrow(*Cap)); | 
|  | 1137 | return CT; | 
|  | 1138 | } | 
|  | 1139 |  | 
|  | 1140 | case Expr::CXXNewExprClass: { | 
|  | 1141 | CanThrowResult CT; | 
|  | 1142 | if (E->isTypeDependent()) | 
|  | 1143 | CT = CT_Dependent; | 
|  | 1144 | else | 
|  | 1145 | CT = canCalleeThrow(*this, E, cast<CXXNewExpr>(E)->getOperatorNew()); | 
|  | 1146 | if (CT == CT_Can) | 
|  | 1147 | return CT; | 
|  | 1148 | return mergeCanThrow(CT, canSubExprsThrow(*this, E)); | 
|  | 1149 | } | 
|  | 1150 |  | 
|  | 1151 | case Expr::CXXDeleteExprClass: { | 
|  | 1152 | CanThrowResult CT; | 
|  | 1153 | QualType DTy = cast<CXXDeleteExpr>(E)->getDestroyedType(); | 
|  | 1154 | if (DTy.isNull() || DTy->isDependentType()) { | 
|  | 1155 | CT = CT_Dependent; | 
|  | 1156 | } else { | 
|  | 1157 | CT = canCalleeThrow(*this, E, | 
|  | 1158 | cast<CXXDeleteExpr>(E)->getOperatorDelete()); | 
|  | 1159 | if (const RecordType *RT = DTy->getAs<RecordType>()) { | 
|  | 1160 | const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); | 
| Eli Friedman | 0423b76 | 2013-06-25 01:24:22 +0000 | [diff] [blame] | 1161 | const CXXDestructorDecl *DD = RD->getDestructor(); | 
|  | 1162 | if (DD) | 
|  | 1163 | CT = mergeCanThrow(CT, canCalleeThrow(*this, E, DD)); | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1164 | } | 
|  | 1165 | if (CT == CT_Can) | 
|  | 1166 | return CT; | 
|  | 1167 | } | 
|  | 1168 | return mergeCanThrow(CT, canSubExprsThrow(*this, E)); | 
|  | 1169 | } | 
|  | 1170 |  | 
|  | 1171 | case Expr::CXXBindTemporaryExprClass: { | 
|  | 1172 | // The bound temporary has to be destroyed again, which might throw. | 
|  | 1173 | CanThrowResult CT = canCalleeThrow(*this, E, | 
|  | 1174 | cast<CXXBindTemporaryExpr>(E)->getTemporary()->getDestructor()); | 
|  | 1175 | if (CT == CT_Can) | 
|  | 1176 | return CT; | 
|  | 1177 | return mergeCanThrow(CT, canSubExprsThrow(*this, E)); | 
|  | 1178 | } | 
|  | 1179 |  | 
|  | 1180 | // ObjC message sends are like function calls, but never have exception | 
|  | 1181 | // specs. | 
|  | 1182 | case Expr::ObjCMessageExprClass: | 
|  | 1183 | case Expr::ObjCPropertyRefExprClass: | 
|  | 1184 | case Expr::ObjCSubscriptRefExprClass: | 
|  | 1185 | return CT_Can; | 
|  | 1186 |  | 
|  | 1187 | // All the ObjC literals that are implemented as calls are | 
|  | 1188 | // potentially throwing unless we decide to close off that | 
|  | 1189 | // possibility. | 
|  | 1190 | case Expr::ObjCArrayLiteralClass: | 
|  | 1191 | case Expr::ObjCDictionaryLiteralClass: | 
| Patrick Beard | 0caa394 | 2012-04-19 00:25:12 +0000 | [diff] [blame] | 1192 | case Expr::ObjCBoxedExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1193 | return CT_Can; | 
|  | 1194 |  | 
|  | 1195 | // Many other things have subexpressions, so we have to test those. | 
|  | 1196 | // Some are simple: | 
| Richard Smith | 9f690bd | 2015-10-27 06:02:45 +0000 | [diff] [blame] | 1197 | case Expr::CoawaitExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1198 | case Expr::ConditionalOperatorClass: | 
|  | 1199 | case Expr::CompoundLiteralExprClass: | 
| Richard Smith | 9f690bd | 2015-10-27 06:02:45 +0000 | [diff] [blame] | 1200 | case Expr::CoyieldExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1201 | case Expr::CXXConstCastExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1202 | case Expr::CXXReinterpretCastExprClass: | 
| Richard Smith | 778dc0f | 2019-10-19 00:04:38 +0000 | [diff] [blame] | 1203 | case Expr::CXXRewrittenBinaryOperatorClass: | 
| Erik Pilkington | eee944e | 2019-07-02 18:28:13 +0000 | [diff] [blame] | 1204 | case Expr::BuiltinBitCastExprClass: | 
| Richard Smith | cc1b96d | 2013-06-12 22:31:48 +0000 | [diff] [blame] | 1205 | case Expr::CXXStdInitializerListExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1206 | case Expr::DesignatedInitExprClass: | 
| Yunzhong Gao | cb77930 | 2015-06-10 00:27:52 +0000 | [diff] [blame] | 1207 | case Expr::DesignatedInitUpdateExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1208 | case Expr::ExprWithCleanupsClass: | 
|  | 1209 | case Expr::ExtVectorElementExprClass: | 
|  | 1210 | case Expr::InitListExprClass: | 
| Richard Smith | 410306b | 2016-12-12 02:53:20 +0000 | [diff] [blame] | 1211 | case Expr::ArrayInitLoopExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1212 | case Expr::MemberExprClass: | 
|  | 1213 | case Expr::ObjCIsaExprClass: | 
|  | 1214 | case Expr::ObjCIvarRefExprClass: | 
|  | 1215 | case Expr::ParenExprClass: | 
|  | 1216 | case Expr::ParenListExprClass: | 
|  | 1217 | case Expr::ShuffleVectorExprClass: | 
| Hal Finkel | c4d7c82 | 2013-09-18 03:29:45 +0000 | [diff] [blame] | 1218 | case Expr::ConvertVectorExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1219 | case Expr::VAArgExprClass: | 
|  | 1220 | return canSubExprsThrow(*this, E); | 
|  | 1221 |  | 
|  | 1222 | // Some might be dependent for other reasons. | 
|  | 1223 | case Expr::ArraySubscriptExprClass: | 
| Alexey Bataev | 1a3320e | 2015-08-25 14:24:04 +0000 | [diff] [blame] | 1224 | case Expr::OMPArraySectionExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1225 | case Expr::BinaryOperatorClass: | 
| Eric Fiselier | 20f25cb | 2017-03-06 23:38:15 +0000 | [diff] [blame] | 1226 | case Expr::DependentCoawaitExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1227 | case Expr::CompoundAssignOperatorClass: | 
|  | 1228 | case Expr::CStyleCastExprClass: | 
|  | 1229 | case Expr::CXXStaticCastExprClass: | 
|  | 1230 | case Expr::CXXFunctionalCastExprClass: | 
|  | 1231 | case Expr::ImplicitCastExprClass: | 
|  | 1232 | case Expr::MaterializeTemporaryExprClass: | 
|  | 1233 | case Expr::UnaryOperatorClass: { | 
|  | 1234 | CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot; | 
|  | 1235 | return mergeCanThrow(CT, canSubExprsThrow(*this, E)); | 
|  | 1236 | } | 
|  | 1237 |  | 
|  | 1238 | // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms. | 
|  | 1239 | case Expr::StmtExprClass: | 
|  | 1240 | return CT_Can; | 
|  | 1241 |  | 
| Richard Smith | 852c9db | 2013-04-20 22:23:05 +0000 | [diff] [blame] | 1242 | case Expr::CXXDefaultArgExprClass: | 
|  | 1243 | return canThrow(cast<CXXDefaultArgExpr>(E)->getExpr()); | 
|  | 1244 |  | 
|  | 1245 | case Expr::CXXDefaultInitExprClass: | 
|  | 1246 | return canThrow(cast<CXXDefaultInitExpr>(E)->getExpr()); | 
|  | 1247 |  | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1248 | case Expr::ChooseExprClass: | 
|  | 1249 | if (E->isTypeDependent() || E->isValueDependent()) | 
|  | 1250 | return CT_Dependent; | 
| Eli Friedman | 75807f2 | 2013-07-20 00:40:58 +0000 | [diff] [blame] | 1251 | return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr()); | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1252 |  | 
|  | 1253 | case Expr::GenericSelectionExprClass: | 
|  | 1254 | if (cast<GenericSelectionExpr>(E)->isResultDependent()) | 
|  | 1255 | return CT_Dependent; | 
|  | 1256 | return canThrow(cast<GenericSelectionExpr>(E)->getResultExpr()); | 
|  | 1257 |  | 
|  | 1258 | // Some expressions are always dependent. | 
|  | 1259 | case Expr::CXXDependentScopeMemberExprClass: | 
|  | 1260 | case Expr::CXXUnresolvedConstructExprClass: | 
|  | 1261 | case Expr::DependentScopeDeclRefExprClass: | 
| Richard Smith | 0f0af19 | 2014-11-08 05:07:16 +0000 | [diff] [blame] | 1262 | case Expr::CXXFoldExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1263 | return CT_Dependent; | 
|  | 1264 |  | 
|  | 1265 | case Expr::AsTypeExprClass: | 
|  | 1266 | case Expr::BinaryConditionalOperatorClass: | 
|  | 1267 | case Expr::BlockExprClass: | 
|  | 1268 | case Expr::CUDAKernelCallExprClass: | 
|  | 1269 | case Expr::DeclRefExprClass: | 
|  | 1270 | case Expr::ObjCBridgedCastExprClass: | 
|  | 1271 | case Expr::ObjCIndirectCopyRestoreExprClass: | 
|  | 1272 | case Expr::ObjCProtocolExprClass: | 
|  | 1273 | case Expr::ObjCSelectorExprClass: | 
| Erik Pilkington | 29099de | 2016-07-16 00:35:23 +0000 | [diff] [blame] | 1274 | case Expr::ObjCAvailabilityCheckExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1275 | case Expr::OffsetOfExprClass: | 
|  | 1276 | case Expr::PackExpansionExprClass: | 
|  | 1277 | case Expr::PseudoObjectExprClass: | 
|  | 1278 | case Expr::SubstNonTypeTemplateParmExprClass: | 
|  | 1279 | case Expr::SubstNonTypeTemplateParmPackExprClass: | 
| Richard Smith | b15fe3a | 2012-09-12 00:56:43 +0000 | [diff] [blame] | 1280 | case Expr::FunctionParmPackExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1281 | case Expr::UnaryExprOrTypeTraitExprClass: | 
|  | 1282 | case Expr::UnresolvedLookupExprClass: | 
|  | 1283 | case Expr::UnresolvedMemberExprClass: | 
| Kaelyn Takata | e1f49d5 | 2014-10-27 18:07:20 +0000 | [diff] [blame] | 1284 | case Expr::TypoExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1285 | // FIXME: Can any of the above throw?  If so, when? | 
|  | 1286 | return CT_Cannot; | 
|  | 1287 |  | 
|  | 1288 | case Expr::AddrLabelExprClass: | 
|  | 1289 | case Expr::ArrayTypeTraitExprClass: | 
|  | 1290 | case Expr::AtomicExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1291 | case Expr::TypeTraitExprClass: | 
|  | 1292 | case Expr::CXXBoolLiteralExprClass: | 
|  | 1293 | case Expr::CXXNoexceptExprClass: | 
|  | 1294 | case Expr::CXXNullPtrLiteralExprClass: | 
|  | 1295 | case Expr::CXXPseudoDestructorExprClass: | 
|  | 1296 | case Expr::CXXScalarValueInitExprClass: | 
|  | 1297 | case Expr::CXXThisExprClass: | 
|  | 1298 | case Expr::CXXUuidofExprClass: | 
|  | 1299 | case Expr::CharacterLiteralClass: | 
|  | 1300 | case Expr::ExpressionTraitExprClass: | 
|  | 1301 | case Expr::FloatingLiteralClass: | 
|  | 1302 | case Expr::GNUNullExprClass: | 
|  | 1303 | case Expr::ImaginaryLiteralClass: | 
|  | 1304 | case Expr::ImplicitValueInitExprClass: | 
|  | 1305 | case Expr::IntegerLiteralClass: | 
| Leonard Chan | db01c3a | 2018-06-20 17:19:40 +0000 | [diff] [blame] | 1306 | case Expr::FixedPointLiteralClass: | 
| Richard Smith | 410306b | 2016-12-12 02:53:20 +0000 | [diff] [blame] | 1307 | case Expr::ArrayInitIndexExprClass: | 
| Yunzhong Gao | cb77930 | 2015-06-10 00:27:52 +0000 | [diff] [blame] | 1308 | case Expr::NoInitExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1309 | case Expr::ObjCEncodeExprClass: | 
|  | 1310 | case Expr::ObjCStringLiteralClass: | 
|  | 1311 | case Expr::ObjCBoolLiteralExprClass: | 
|  | 1312 | case Expr::OpaqueValueExprClass: | 
|  | 1313 | case Expr::PredefinedExprClass: | 
|  | 1314 | case Expr::SizeOfPackExprClass: | 
|  | 1315 | case Expr::StringLiteralClass: | 
| Eric Fiselier | 708afb5 | 2019-05-16 21:04:15 +0000 | [diff] [blame] | 1316 | case Expr::SourceLocExprClass: | 
| Saar Raz | 5d98ba6 | 2019-10-15 15:24:26 +0000 | [diff] [blame] | 1317 | case Expr::ConceptSpecializationExprClass: | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1318 | // These expressions can never throw. | 
|  | 1319 | return CT_Cannot; | 
|  | 1320 |  | 
| John McCall | 5e77d76 | 2013-04-16 07:28:30 +0000 | [diff] [blame] | 1321 | case Expr::MSPropertyRefExprClass: | 
| Alexey Bataev | f763027 | 2015-11-25 12:01:00 +0000 | [diff] [blame] | 1322 | case Expr::MSPropertySubscriptExprClass: | 
| John McCall | 5e77d76 | 2013-04-16 07:28:30 +0000 | [diff] [blame] | 1323 | llvm_unreachable("Invalid class for expression"); | 
|  | 1324 |  | 
| Richard Smith | f623c96 | 2012-04-17 00:58:00 +0000 | [diff] [blame] | 1325 | #define STMT(CLASS, PARENT) case Expr::CLASS##Class: | 
|  | 1326 | #define STMT_RANGE(Base, First, Last) | 
|  | 1327 | #define LAST_STMT_RANGE(BASE, FIRST, LAST) | 
|  | 1328 | #define EXPR(CLASS, PARENT) | 
|  | 1329 | #define ABSTRACT_STMT(STMT) | 
|  | 1330 | #include "clang/AST/StmtNodes.inc" | 
|  | 1331 | case Expr::NoStmtClass: | 
|  | 1332 | llvm_unreachable("Invalid class for expression"); | 
|  | 1333 | } | 
|  | 1334 | llvm_unreachable("Bogus StmtClass"); | 
|  | 1335 | } | 
|  | 1336 |  | 
| Sebastian Redl | 4915e63 | 2009-10-11 09:03:14 +0000 | [diff] [blame] | 1337 | } // end namespace clang |