File: | clang/lib/Sema/SemaExceptionSpec.cpp |
Warning: | line 1043, column 49 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===// | ||||||||
2 | // | ||||||||
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 | ||||||||
6 | // | ||||||||
7 | //===----------------------------------------------------------------------===// | ||||||||
8 | // | ||||||||
9 | // This file provides Sema routines for C++ exception specification testing. | ||||||||
10 | // | ||||||||
11 | //===----------------------------------------------------------------------===// | ||||||||
12 | |||||||||
13 | #include "clang/Sema/SemaInternal.h" | ||||||||
14 | #include "clang/AST/ASTMutationListener.h" | ||||||||
15 | #include "clang/AST/CXXInheritance.h" | ||||||||
16 | #include "clang/AST/Expr.h" | ||||||||
17 | #include "clang/AST/ExprCXX.h" | ||||||||
18 | #include "clang/AST/StmtObjC.h" | ||||||||
19 | #include "clang/AST/TypeLoc.h" | ||||||||
20 | #include "clang/Basic/Diagnostic.h" | ||||||||
21 | #include "clang/Basic/SourceManager.h" | ||||||||
22 | #include "llvm/ADT/SmallPtrSet.h" | ||||||||
23 | #include "llvm/ADT/SmallString.h" | ||||||||
24 | |||||||||
25 | namespace clang { | ||||||||
26 | |||||||||
27 | static const FunctionProtoType *GetUnderlyingFunction(QualType T) | ||||||||
28 | { | ||||||||
29 | if (const PointerType *PtrTy = T->getAs<PointerType>()) | ||||||||
30 | T = PtrTy->getPointeeType(); | ||||||||
31 | else if (const ReferenceType *RefTy = T->getAs<ReferenceType>()) | ||||||||
32 | T = RefTy->getPointeeType(); | ||||||||
33 | else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>()) | ||||||||
34 | T = MPTy->getPointeeType(); | ||||||||
35 | return T->getAs<FunctionProtoType>(); | ||||||||
36 | } | ||||||||
37 | |||||||||
38 | /// HACK: libstdc++ has a bug where it shadows std::swap with a member | ||||||||
39 | /// swap function then tries to call std::swap unqualified from the exception | ||||||||
40 | /// specification of that function. This function detects whether we're in | ||||||||
41 | /// such a case and turns off delay-parsing of exception specifications. | ||||||||
42 | bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) { | ||||||||
43 | auto *RD = dyn_cast<CXXRecordDecl>(CurContext); | ||||||||
44 | |||||||||
45 | // All the problem cases are member functions named "swap" within class | ||||||||
46 | // templates declared directly within namespace std or std::__debug or | ||||||||
47 | // std::__profile. | ||||||||
48 | if (!RD || !RD->getIdentifier() || !RD->getDescribedClassTemplate() || | ||||||||
49 | !D.getIdentifier() || !D.getIdentifier()->isStr("swap")) | ||||||||
50 | return false; | ||||||||
51 | |||||||||
52 | auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext()); | ||||||||
53 | if (!ND) | ||||||||
54 | return false; | ||||||||
55 | |||||||||
56 | bool IsInStd = ND->isStdNamespace(); | ||||||||
57 | if (!IsInStd) { | ||||||||
58 | // This isn't a direct member of namespace std, but it might still be | ||||||||
59 | // libstdc++'s std::__debug::array or std::__profile::array. | ||||||||
60 | IdentifierInfo *II = ND->getIdentifier(); | ||||||||
61 | if (!II || !(II->isStr("__debug") || II->isStr("__profile")) || | ||||||||
62 | !ND->isInStdNamespace()) | ||||||||
63 | return false; | ||||||||
64 | } | ||||||||
65 | |||||||||
66 | // Only apply this hack within a system header. | ||||||||
67 | if (!Context.getSourceManager().isInSystemHeader(D.getBeginLoc())) | ||||||||
68 | return false; | ||||||||
69 | |||||||||
70 | return llvm::StringSwitch<bool>(RD->getIdentifier()->getName()) | ||||||||
71 | .Case("array", true) | ||||||||
72 | .Case("pair", IsInStd) | ||||||||
73 | .Case("priority_queue", IsInStd) | ||||||||
74 | .Case("stack", IsInStd) | ||||||||
75 | .Case("queue", IsInStd) | ||||||||
76 | .Default(false); | ||||||||
77 | } | ||||||||
78 | |||||||||
79 | ExprResult Sema::ActOnNoexceptSpec(SourceLocation NoexceptLoc, | ||||||||
80 | Expr *NoexceptExpr, | ||||||||
81 | ExceptionSpecificationType &EST) { | ||||||||
82 | // FIXME: This is bogus, a noexcept expression is not a condition. | ||||||||
83 | ExprResult Converted = CheckBooleanCondition(NoexceptLoc, NoexceptExpr); | ||||||||
84 | if (Converted.isInvalid()) { | ||||||||
85 | EST = EST_NoexceptFalse; | ||||||||
86 | |||||||||
87 | // Fill in an expression of 'false' as a fixup. | ||||||||
88 | auto *BoolExpr = new (Context) | ||||||||
89 | CXXBoolLiteralExpr(false, Context.BoolTy, NoexceptExpr->getBeginLoc()); | ||||||||
90 | llvm::APSInt Value{1}; | ||||||||
91 | Value = 0; | ||||||||
92 | return ConstantExpr::Create(Context, BoolExpr, APValue{Value}); | ||||||||
93 | } | ||||||||
94 | |||||||||
95 | if (Converted.get()->isValueDependent()) { | ||||||||
96 | EST = EST_DependentNoexcept; | ||||||||
97 | return Converted; | ||||||||
98 | } | ||||||||
99 | |||||||||
100 | llvm::APSInt Result; | ||||||||
101 | Converted = VerifyIntegerConstantExpression( | ||||||||
102 | Converted.get(), &Result, | ||||||||
103 | diag::err_noexcept_needs_constant_expression, | ||||||||
104 | /*AllowFold*/ false); | ||||||||
105 | if (!Converted.isInvalid()) | ||||||||
106 | EST = !Result ? EST_NoexceptFalse : EST_NoexceptTrue; | ||||||||
107 | return Converted; | ||||||||
108 | } | ||||||||
109 | |||||||||
110 | /// CheckSpecifiedExceptionType - Check if the given type is valid in an | ||||||||
111 | /// exception specification. Incomplete types, or pointers to incomplete types | ||||||||
112 | /// other than void are not allowed. | ||||||||
113 | /// | ||||||||
114 | /// \param[in,out] T The exception type. This will be decayed to a pointer type | ||||||||
115 | /// when the input is an array or a function type. | ||||||||
116 | bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) { | ||||||||
117 | // C++11 [except.spec]p2: | ||||||||
118 | // A type cv T, "array of T", or "function returning T" denoted | ||||||||
119 | // in an exception-specification is adjusted to type T, "pointer to T", or | ||||||||
120 | // "pointer to function returning T", respectively. | ||||||||
121 | // | ||||||||
122 | // We also apply this rule in C++98. | ||||||||
123 | if (T->isArrayType()) | ||||||||
124 | T = Context.getArrayDecayedType(T); | ||||||||
125 | else if (T->isFunctionType()) | ||||||||
126 | T = Context.getPointerType(T); | ||||||||
127 | |||||||||
128 | int Kind = 0; | ||||||||
129 | QualType PointeeT = T; | ||||||||
130 | if (const PointerType *PT = T->getAs<PointerType>()) { | ||||||||
131 | PointeeT = PT->getPointeeType(); | ||||||||
132 | Kind = 1; | ||||||||
133 | |||||||||
134 | // cv void* is explicitly permitted, despite being a pointer to an | ||||||||
135 | // incomplete type. | ||||||||
136 | if (PointeeT->isVoidType()) | ||||||||
137 | return false; | ||||||||
138 | } else if (const ReferenceType *RT = T->getAs<ReferenceType>()) { | ||||||||
139 | PointeeT = RT->getPointeeType(); | ||||||||
140 | Kind = 2; | ||||||||
141 | |||||||||
142 | if (RT->isRValueReferenceType()) { | ||||||||
143 | // C++11 [except.spec]p2: | ||||||||
144 | // A type denoted in an exception-specification shall not denote [...] | ||||||||
145 | // an rvalue reference type. | ||||||||
146 | Diag(Range.getBegin(), diag::err_rref_in_exception_spec) | ||||||||
147 | << T << Range; | ||||||||
148 | return true; | ||||||||
149 | } | ||||||||
150 | } | ||||||||
151 | |||||||||
152 | // C++11 [except.spec]p2: | ||||||||
153 | // A type denoted in an exception-specification shall not denote an | ||||||||
154 | // incomplete type other than a class currently being defined [...]. | ||||||||
155 | // A type denoted in an exception-specification shall not denote a | ||||||||
156 | // pointer or reference to an incomplete type, other than (cv) void* or a | ||||||||
157 | // pointer or reference to a class currently being defined. | ||||||||
158 | // In Microsoft mode, downgrade this to a warning. | ||||||||
159 | unsigned DiagID = diag::err_incomplete_in_exception_spec; | ||||||||
160 | bool ReturnValueOnError = true; | ||||||||
161 | if (getLangOpts().MSVCCompat) { | ||||||||
162 | DiagID = diag::ext_incomplete_in_exception_spec; | ||||||||
163 | ReturnValueOnError = false; | ||||||||
164 | } | ||||||||
165 | if (!(PointeeT->isRecordType() && | ||||||||
166 | PointeeT->castAs<RecordType>()->isBeingDefined()) && | ||||||||
167 | RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range)) | ||||||||
168 | return ReturnValueOnError; | ||||||||
169 | |||||||||
170 | return false; | ||||||||
171 | } | ||||||||
172 | |||||||||
173 | /// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer | ||||||||
174 | /// to member to a function with an exception specification. This means that | ||||||||
175 | /// it is invalid to add another level of indirection. | ||||||||
176 | bool Sema::CheckDistantExceptionSpec(QualType T) { | ||||||||
177 | // C++17 removes this rule in favor of putting exception specifications into | ||||||||
178 | // the type system. | ||||||||
179 | if (getLangOpts().CPlusPlus17) | ||||||||
180 | return false; | ||||||||
181 | |||||||||
182 | if (const PointerType *PT = T->getAs<PointerType>()) | ||||||||
183 | T = PT->getPointeeType(); | ||||||||
184 | else if (const MemberPointerType *PT = T->getAs<MemberPointerType>()) | ||||||||
185 | T = PT->getPointeeType(); | ||||||||
186 | else | ||||||||
187 | return false; | ||||||||
188 | |||||||||
189 | const FunctionProtoType *FnT = T->getAs<FunctionProtoType>(); | ||||||||
190 | if (!FnT) | ||||||||
191 | return false; | ||||||||
192 | |||||||||
193 | return FnT->hasExceptionSpec(); | ||||||||
194 | } | ||||||||
195 | |||||||||
196 | const FunctionProtoType * | ||||||||
197 | Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { | ||||||||
198 | if (FPT->getExceptionSpecType() == EST_Unparsed) { | ||||||||
199 | Diag(Loc, diag::err_exception_spec_not_parsed); | ||||||||
200 | return nullptr; | ||||||||
201 | } | ||||||||
202 | |||||||||
203 | if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) | ||||||||
204 | return FPT; | ||||||||
205 | |||||||||
206 | FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl(); | ||||||||
207 | const FunctionProtoType *SourceFPT = | ||||||||
208 | SourceDecl->getType()->castAs<FunctionProtoType>(); | ||||||||
209 | |||||||||
210 | // If the exception specification has already been resolved, just return it. | ||||||||
211 | if (!isUnresolvedExceptionSpec(SourceFPT->getExceptionSpecType())) | ||||||||
212 | return SourceFPT; | ||||||||
213 | |||||||||
214 | // Compute or instantiate the exception specification now. | ||||||||
215 | if (SourceFPT->getExceptionSpecType() == EST_Unevaluated) | ||||||||
216 | EvaluateImplicitExceptionSpec(Loc, SourceDecl); | ||||||||
217 | else | ||||||||
218 | InstantiateExceptionSpec(Loc, SourceDecl); | ||||||||
219 | |||||||||
220 | const FunctionProtoType *Proto = | ||||||||
221 | SourceDecl->getType()->castAs<FunctionProtoType>(); | ||||||||
222 | if (Proto->getExceptionSpecType() == clang::EST_Unparsed) { | ||||||||
223 | Diag(Loc, diag::err_exception_spec_not_parsed); | ||||||||
224 | Proto = nullptr; | ||||||||
225 | } | ||||||||
226 | return Proto; | ||||||||
227 | } | ||||||||
228 | |||||||||
229 | void | ||||||||
230 | Sema::UpdateExceptionSpec(FunctionDecl *FD, | ||||||||
231 | const FunctionProtoType::ExceptionSpecInfo &ESI) { | ||||||||
232 | // If we've fully resolved the exception specification, notify listeners. | ||||||||
233 | if (!isUnresolvedExceptionSpec(ESI.Type)) | ||||||||
234 | if (auto *Listener = getASTMutationListener()) | ||||||||
235 | Listener->ResolvedExceptionSpec(FD); | ||||||||
236 | |||||||||
237 | for (FunctionDecl *Redecl : FD->redecls()) | ||||||||
238 | Context.adjustExceptionSpec(Redecl, ESI); | ||||||||
239 | } | ||||||||
240 | |||||||||
241 | static bool exceptionSpecNotKnownYet(const FunctionDecl *FD) { | ||||||||
242 | auto *MD = dyn_cast<CXXMethodDecl>(FD); | ||||||||
243 | if (!MD) | ||||||||
244 | return false; | ||||||||
245 | |||||||||
246 | auto EST = MD->getType()->castAs<FunctionProtoType>()->getExceptionSpecType(); | ||||||||
247 | return EST == EST_Unparsed || | ||||||||
248 | (EST == EST_Unevaluated && MD->getParent()->isBeingDefined()); | ||||||||
249 | } | ||||||||
250 | |||||||||
251 | static bool CheckEquivalentExceptionSpecImpl( | ||||||||
252 | Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID, | ||||||||
253 | const FunctionProtoType *Old, SourceLocation OldLoc, | ||||||||
254 | const FunctionProtoType *New, SourceLocation NewLoc, | ||||||||
255 | bool *MissingExceptionSpecification = nullptr, | ||||||||
256 | bool *MissingEmptyExceptionSpecification = nullptr, | ||||||||
257 | bool AllowNoexceptAllMatchWithNoSpec = false, bool IsOperatorNew = false); | ||||||||
258 | |||||||||
259 | /// Determine whether a function has an implicitly-generated exception | ||||||||
260 | /// specification. | ||||||||
261 | static bool hasImplicitExceptionSpec(FunctionDecl *Decl) { | ||||||||
262 | if (!isa<CXXDestructorDecl>(Decl) && | ||||||||
263 | Decl->getDeclName().getCXXOverloadedOperator() != OO_Delete && | ||||||||
264 | Decl->getDeclName().getCXXOverloadedOperator() != OO_Array_Delete) | ||||||||
265 | return false; | ||||||||
266 | |||||||||
267 | // For a function that the user didn't declare: | ||||||||
268 | // - if this is a destructor, its exception specification is implicit. | ||||||||
269 | // - if this is 'operator delete' or 'operator delete[]', the exception | ||||||||
270 | // specification is as-if an explicit exception specification was given | ||||||||
271 | // (per [basic.stc.dynamic]p2). | ||||||||
272 | if (!Decl->getTypeSourceInfo()) | ||||||||
273 | return isa<CXXDestructorDecl>(Decl); | ||||||||
274 | |||||||||
275 | auto *Ty = Decl->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>(); | ||||||||
276 | return !Ty->hasExceptionSpec(); | ||||||||
277 | } | ||||||||
278 | |||||||||
279 | bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { | ||||||||
280 | // Just completely ignore this under -fno-exceptions prior to C++17. | ||||||||
281 | // In C++17 onwards, the exception specification is part of the type and | ||||||||
282 | // we will diagnose mismatches anyway, so it's better to check for them here. | ||||||||
283 | if (!getLangOpts().CXXExceptions && !getLangOpts().CPlusPlus17) | ||||||||
284 | return false; | ||||||||
285 | |||||||||
286 | OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator(); | ||||||||
287 | bool IsOperatorNew = OO == OO_New || OO == OO_Array_New; | ||||||||
288 | bool MissingExceptionSpecification = false; | ||||||||
289 | bool MissingEmptyExceptionSpecification = false; | ||||||||
290 | |||||||||
291 | unsigned DiagID = diag::err_mismatched_exception_spec; | ||||||||
292 | bool ReturnValueOnError = true; | ||||||||
293 | if (getLangOpts().MSVCCompat) { | ||||||||
294 | DiagID = diag::ext_mismatched_exception_spec; | ||||||||
295 | ReturnValueOnError = false; | ||||||||
296 | } | ||||||||
297 | |||||||||
298 | // If we're befriending a member function of a class that's currently being | ||||||||
299 | // defined, we might not be able to work out its exception specification yet. | ||||||||
300 | // If not, defer the check until later. | ||||||||
301 | if (exceptionSpecNotKnownYet(Old) || exceptionSpecNotKnownYet(New)) { | ||||||||
302 | DelayedEquivalentExceptionSpecChecks.push_back({New, Old}); | ||||||||
303 | return false; | ||||||||
304 | } | ||||||||
305 | |||||||||
306 | // Check the types as written: they must match before any exception | ||||||||
307 | // specification adjustment is applied. | ||||||||
308 | if (!CheckEquivalentExceptionSpecImpl( | ||||||||
309 | *this, PDiag(DiagID), PDiag(diag::note_previous_declaration), | ||||||||
310 | Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), | ||||||||
311 | New->getType()->getAs<FunctionProtoType>(), New->getLocation(), | ||||||||
312 | &MissingExceptionSpecification, &MissingEmptyExceptionSpecification, | ||||||||
313 | /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) { | ||||||||
314 | // C++11 [except.spec]p4 [DR1492]: | ||||||||
315 | // If a declaration of a function has an implicit | ||||||||
316 | // exception-specification, other declarations of the function shall | ||||||||
317 | // not specify an exception-specification. | ||||||||
318 | if (getLangOpts().CPlusPlus11 && getLangOpts().CXXExceptions && | ||||||||
319 | hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) { | ||||||||
320 | Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch) | ||||||||
321 | << hasImplicitExceptionSpec(Old); | ||||||||
322 | if (Old->getLocation().isValid()) | ||||||||
323 | Diag(Old->getLocation(), diag::note_previous_declaration); | ||||||||
324 | } | ||||||||
325 | return false; | ||||||||
326 | } | ||||||||
327 | |||||||||
328 | // The failure was something other than an missing exception | ||||||||
329 | // specification; return an error, except in MS mode where this is a warning. | ||||||||
330 | if (!MissingExceptionSpecification) | ||||||||
331 | return ReturnValueOnError; | ||||||||
332 | |||||||||
333 | const FunctionProtoType *NewProto = | ||||||||
334 | New->getType()->castAs<FunctionProtoType>(); | ||||||||
335 | |||||||||
336 | // The new function declaration is only missing an empty exception | ||||||||
337 | // specification "throw()". If the throw() specification came from a | ||||||||
338 | // function in a system header that has C linkage, just add an empty | ||||||||
339 | // exception specification to the "new" declaration. Note that C library | ||||||||
340 | // implementations are permitted to add these nothrow exception | ||||||||
341 | // specifications. | ||||||||
342 | // | ||||||||
343 | // Likewise if the old function is a builtin. | ||||||||
344 | if (MissingEmptyExceptionSpecification && NewProto && | ||||||||
345 | (Old->getLocation().isInvalid() || | ||||||||
346 | Context.getSourceManager().isInSystemHeader(Old->getLocation()) || | ||||||||
347 | Old->getBuiltinID()) && | ||||||||
348 | Old->isExternC()) { | ||||||||
349 | New->setType(Context.getFunctionType( | ||||||||
350 | NewProto->getReturnType(), NewProto->getParamTypes(), | ||||||||
351 | NewProto->getExtProtoInfo().withExceptionSpec(EST_DynamicNone))); | ||||||||
352 | return false; | ||||||||
353 | } | ||||||||
354 | |||||||||
355 | const FunctionProtoType *OldProto = | ||||||||
356 | Old->getType()->castAs<FunctionProtoType>(); | ||||||||
357 | |||||||||
358 | FunctionProtoType::ExceptionSpecInfo ESI = OldProto->getExceptionSpecType(); | ||||||||
359 | if (ESI.Type == EST_Dynamic) { | ||||||||
360 | // FIXME: What if the exceptions are described in terms of the old | ||||||||
361 | // prototype's parameters? | ||||||||
362 | ESI.Exceptions = OldProto->exceptions(); | ||||||||
363 | } | ||||||||
364 | |||||||||
365 | if (ESI.Type == EST_NoexceptFalse) | ||||||||
366 | ESI.Type = EST_None; | ||||||||
367 | if (ESI.Type == EST_NoexceptTrue) | ||||||||
368 | ESI.Type = EST_BasicNoexcept; | ||||||||
369 | |||||||||
370 | // For dependent noexcept, we can't just take the expression from the old | ||||||||
371 | // prototype. It likely contains references to the old prototype's parameters. | ||||||||
372 | if (ESI.Type == EST_DependentNoexcept) { | ||||||||
373 | New->setInvalidDecl(); | ||||||||
374 | } else { | ||||||||
375 | // Update the type of the function with the appropriate exception | ||||||||
376 | // specification. | ||||||||
377 | New->setType(Context.getFunctionType( | ||||||||
378 | NewProto->getReturnType(), NewProto->getParamTypes(), | ||||||||
379 | NewProto->getExtProtoInfo().withExceptionSpec(ESI))); | ||||||||
380 | } | ||||||||
381 | |||||||||
382 | if (getLangOpts().MSVCCompat && ESI.Type != EST_DependentNoexcept) { | ||||||||
383 | // Allow missing exception specifications in redeclarations as an extension. | ||||||||
384 | DiagID = diag::ext_ms_missing_exception_specification; | ||||||||
385 | ReturnValueOnError = false; | ||||||||
386 | } else if (New->isReplaceableGlobalAllocationFunction() && | ||||||||
387 | ESI.Type != EST_DependentNoexcept) { | ||||||||
388 | // Allow missing exception specifications in redeclarations as an extension, | ||||||||
389 | // when declaring a replaceable global allocation function. | ||||||||
390 | DiagID = diag::ext_missing_exception_specification; | ||||||||
391 | ReturnValueOnError = false; | ||||||||
392 | } else if (ESI.Type == EST_NoThrow) { | ||||||||
393 | // Allow missing attribute 'nothrow' in redeclarations, since this is a very | ||||||||
394 | // common omission. | ||||||||
395 | DiagID = diag::ext_missing_exception_specification; | ||||||||
396 | ReturnValueOnError = false; | ||||||||
397 | } else { | ||||||||
398 | DiagID = diag::err_missing_exception_specification; | ||||||||
399 | ReturnValueOnError = true; | ||||||||
400 | } | ||||||||
401 | |||||||||
402 | // Warn about the lack of exception specification. | ||||||||
403 | SmallString<128> ExceptionSpecString; | ||||||||
404 | llvm::raw_svector_ostream OS(ExceptionSpecString); | ||||||||
405 | switch (OldProto->getExceptionSpecType()) { | ||||||||
406 | case EST_DynamicNone: | ||||||||
407 | OS << "throw()"; | ||||||||
408 | break; | ||||||||
409 | |||||||||
410 | case EST_Dynamic: { | ||||||||
411 | OS << "throw("; | ||||||||
412 | bool OnFirstException = true; | ||||||||
413 | for (const auto &E : OldProto->exceptions()) { | ||||||||
414 | if (OnFirstException) | ||||||||
415 | OnFirstException = false; | ||||||||
416 | else | ||||||||
417 | OS << ", "; | ||||||||
418 | |||||||||
419 | OS << E.getAsString(getPrintingPolicy()); | ||||||||
420 | } | ||||||||
421 | OS << ")"; | ||||||||
422 | break; | ||||||||
423 | } | ||||||||
424 | |||||||||
425 | case EST_BasicNoexcept: | ||||||||
426 | OS << "noexcept"; | ||||||||
427 | break; | ||||||||
428 | |||||||||
429 | case EST_DependentNoexcept: | ||||||||
430 | case EST_NoexceptFalse: | ||||||||
431 | case EST_NoexceptTrue: | ||||||||
432 | OS << "noexcept("; | ||||||||
433 | assert(OldProto->getNoexceptExpr() != nullptr && "Expected non-null Expr")((OldProto->getNoexceptExpr() != nullptr && "Expected non-null Expr" ) ? static_cast<void> (0) : __assert_fail ("OldProto->getNoexceptExpr() != nullptr && \"Expected non-null Expr\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 433, __PRETTY_FUNCTION__)); | ||||||||
434 | OldProto->getNoexceptExpr()->printPretty(OS, nullptr, getPrintingPolicy()); | ||||||||
435 | OS << ")"; | ||||||||
436 | break; | ||||||||
437 | case EST_NoThrow: | ||||||||
438 | OS <<"__attribute__((nothrow))"; | ||||||||
439 | break; | ||||||||
440 | case EST_None: | ||||||||
441 | case EST_MSAny: | ||||||||
442 | case EST_Unevaluated: | ||||||||
443 | case EST_Uninstantiated: | ||||||||
444 | case EST_Unparsed: | ||||||||
445 | llvm_unreachable("This spec type is compatible with none.")::llvm::llvm_unreachable_internal("This spec type is compatible with none." , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 445); | ||||||||
446 | } | ||||||||
447 | |||||||||
448 | SourceLocation FixItLoc; | ||||||||
449 | if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) { | ||||||||
450 | TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens(); | ||||||||
451 | // FIXME: Preserve enough information so that we can produce a correct fixit | ||||||||
452 | // location when there is a trailing return type. | ||||||||
453 | if (auto FTLoc = TL.getAs<FunctionProtoTypeLoc>()) | ||||||||
454 | if (!FTLoc.getTypePtr()->hasTrailingReturn()) | ||||||||
455 | FixItLoc = getLocForEndOfToken(FTLoc.getLocalRangeEnd()); | ||||||||
456 | } | ||||||||
457 | |||||||||
458 | if (FixItLoc.isInvalid()) | ||||||||
459 | Diag(New->getLocation(), DiagID) | ||||||||
460 | << New << OS.str(); | ||||||||
461 | else { | ||||||||
462 | Diag(New->getLocation(), DiagID) | ||||||||
463 | << New << OS.str() | ||||||||
464 | << FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str()); | ||||||||
465 | } | ||||||||
466 | |||||||||
467 | if (Old->getLocation().isValid()) | ||||||||
468 | Diag(Old->getLocation(), diag::note_previous_declaration); | ||||||||
469 | |||||||||
470 | return ReturnValueOnError; | ||||||||
471 | } | ||||||||
472 | |||||||||
473 | /// CheckEquivalentExceptionSpec - Check if the two types have equivalent | ||||||||
474 | /// exception specifications. Exception specifications are equivalent if | ||||||||
475 | /// they allow exactly the same set of exception types. It does not matter how | ||||||||
476 | /// that is achieved. See C++ [except.spec]p2. | ||||||||
477 | bool Sema::CheckEquivalentExceptionSpec( | ||||||||
478 | const FunctionProtoType *Old, SourceLocation OldLoc, | ||||||||
479 | const FunctionProtoType *New, SourceLocation NewLoc) { | ||||||||
480 | if (!getLangOpts().CXXExceptions) | ||||||||
481 | return false; | ||||||||
482 | |||||||||
483 | unsigned DiagID = diag::err_mismatched_exception_spec; | ||||||||
484 | if (getLangOpts().MSVCCompat) | ||||||||
485 | DiagID = diag::ext_mismatched_exception_spec; | ||||||||
486 | bool Result = CheckEquivalentExceptionSpecImpl( | ||||||||
487 | *this, PDiag(DiagID), PDiag(diag::note_previous_declaration), | ||||||||
488 | Old, OldLoc, New, NewLoc); | ||||||||
489 | |||||||||
490 | // In Microsoft mode, mismatching exception specifications just cause a warning. | ||||||||
491 | if (getLangOpts().MSVCCompat) | ||||||||
492 | return false; | ||||||||
493 | return Result; | ||||||||
494 | } | ||||||||
495 | |||||||||
496 | /// CheckEquivalentExceptionSpec - Check if the two types have compatible | ||||||||
497 | /// exception specifications. See C++ [except.spec]p3. | ||||||||
498 | /// | ||||||||
499 | /// \return \c false if the exception specifications match, \c true if there is | ||||||||
500 | /// a problem. If \c true is returned, either a diagnostic has already been | ||||||||
501 | /// produced or \c *MissingExceptionSpecification is set to \c true. | ||||||||
502 | static bool CheckEquivalentExceptionSpecImpl( | ||||||||
503 | Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID, | ||||||||
504 | const FunctionProtoType *Old, SourceLocation OldLoc, | ||||||||
505 | const FunctionProtoType *New, SourceLocation NewLoc, | ||||||||
506 | bool *MissingExceptionSpecification, | ||||||||
507 | bool *MissingEmptyExceptionSpecification, | ||||||||
508 | bool AllowNoexceptAllMatchWithNoSpec, bool IsOperatorNew) { | ||||||||
509 | if (MissingExceptionSpecification) | ||||||||
510 | *MissingExceptionSpecification = false; | ||||||||
511 | |||||||||
512 | if (MissingEmptyExceptionSpecification) | ||||||||
513 | *MissingEmptyExceptionSpecification = false; | ||||||||
514 | |||||||||
515 | Old = S.ResolveExceptionSpec(NewLoc, Old); | ||||||||
516 | if (!Old) | ||||||||
517 | return false; | ||||||||
518 | New = S.ResolveExceptionSpec(NewLoc, New); | ||||||||
519 | if (!New) | ||||||||
520 | return false; | ||||||||
521 | |||||||||
522 | // C++0x [except.spec]p3: Two exception-specifications are compatible if: | ||||||||
523 | // - both are non-throwing, regardless of their form, | ||||||||
524 | // - both have the form noexcept(constant-expression) and the constant- | ||||||||
525 | // expressions are equivalent, | ||||||||
526 | // - both are dynamic-exception-specifications that have the same set of | ||||||||
527 | // adjusted types. | ||||||||
528 | // | ||||||||
529 | // C++0x [except.spec]p12: An exception-specification is non-throwing if it is | ||||||||
530 | // of the form throw(), noexcept, or noexcept(constant-expression) where the | ||||||||
531 | // constant-expression yields true. | ||||||||
532 | // | ||||||||
533 | // C++0x [except.spec]p4: If any declaration of a function has an exception- | ||||||||
534 | // specifier that is not a noexcept-specification allowing all exceptions, | ||||||||
535 | // all declarations [...] of that function shall have a compatible | ||||||||
536 | // exception-specification. | ||||||||
537 | // | ||||||||
538 | // That last point basically means that noexcept(false) matches no spec. | ||||||||
539 | // It's considered when AllowNoexceptAllMatchWithNoSpec is true. | ||||||||
540 | |||||||||
541 | ExceptionSpecificationType OldEST = Old->getExceptionSpecType(); | ||||||||
542 | ExceptionSpecificationType NewEST = New->getExceptionSpecType(); | ||||||||
543 | |||||||||
544 | assert(!isUnresolvedExceptionSpec(OldEST) &&((!isUnresolvedExceptionSpec(OldEST) && !isUnresolvedExceptionSpec (NewEST) && "Shouldn't see unknown exception specifications here" ) ? static_cast<void> (0) : __assert_fail ("!isUnresolvedExceptionSpec(OldEST) && !isUnresolvedExceptionSpec(NewEST) && \"Shouldn't see unknown exception specifications here\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 546, __PRETTY_FUNCTION__)) | ||||||||
545 | !isUnresolvedExceptionSpec(NewEST) &&((!isUnresolvedExceptionSpec(OldEST) && !isUnresolvedExceptionSpec (NewEST) && "Shouldn't see unknown exception specifications here" ) ? static_cast<void> (0) : __assert_fail ("!isUnresolvedExceptionSpec(OldEST) && !isUnresolvedExceptionSpec(NewEST) && \"Shouldn't see unknown exception specifications here\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 546, __PRETTY_FUNCTION__)) | ||||||||
546 | "Shouldn't see unknown exception specifications here")((!isUnresolvedExceptionSpec(OldEST) && !isUnresolvedExceptionSpec (NewEST) && "Shouldn't see unknown exception specifications here" ) ? static_cast<void> (0) : __assert_fail ("!isUnresolvedExceptionSpec(OldEST) && !isUnresolvedExceptionSpec(NewEST) && \"Shouldn't see unknown exception specifications here\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 546, __PRETTY_FUNCTION__)); | ||||||||
547 | |||||||||
548 | CanThrowResult OldCanThrow = Old->canThrow(); | ||||||||
549 | CanThrowResult NewCanThrow = New->canThrow(); | ||||||||
550 | |||||||||
551 | // Any non-throwing specifications are compatible. | ||||||||
552 | if (OldCanThrow == CT_Cannot && NewCanThrow == CT_Cannot) | ||||||||
553 | return false; | ||||||||
554 | |||||||||
555 | // Any throws-anything specifications are usually compatible. | ||||||||
556 | if (OldCanThrow == CT_Can && OldEST != EST_Dynamic && | ||||||||
557 | NewCanThrow == CT_Can && NewEST != EST_Dynamic) { | ||||||||
558 | // The exception is that the absence of an exception specification only | ||||||||
559 | // matches noexcept(false) for functions, as described above. | ||||||||
560 | if (!AllowNoexceptAllMatchWithNoSpec && | ||||||||
561 | ((OldEST == EST_None && NewEST == EST_NoexceptFalse) || | ||||||||
562 | (OldEST == EST_NoexceptFalse && NewEST == EST_None))) { | ||||||||
563 | // This is the disallowed case. | ||||||||
564 | } else { | ||||||||
565 | return false; | ||||||||
566 | } | ||||||||
567 | } | ||||||||
568 | |||||||||
569 | // C++14 [except.spec]p3: | ||||||||
570 | // Two exception-specifications are compatible if [...] both have the form | ||||||||
571 | // noexcept(constant-expression) and the constant-expressions are equivalent | ||||||||
572 | if (OldEST == EST_DependentNoexcept && NewEST == EST_DependentNoexcept) { | ||||||||
573 | llvm::FoldingSetNodeID OldFSN, NewFSN; | ||||||||
574 | Old->getNoexceptExpr()->Profile(OldFSN, S.Context, true); | ||||||||
575 | New->getNoexceptExpr()->Profile(NewFSN, S.Context, true); | ||||||||
576 | if (OldFSN == NewFSN) | ||||||||
577 | return false; | ||||||||
578 | } | ||||||||
579 | |||||||||
580 | // Dynamic exception specifications with the same set of adjusted types | ||||||||
581 | // are compatible. | ||||||||
582 | if (OldEST == EST_Dynamic && NewEST == EST_Dynamic) { | ||||||||
583 | bool Success = true; | ||||||||
584 | // Both have a dynamic exception spec. Collect the first set, then compare | ||||||||
585 | // to the second. | ||||||||
586 | llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes; | ||||||||
587 | for (const auto &I : Old->exceptions()) | ||||||||
588 | OldTypes.insert(S.Context.getCanonicalType(I).getUnqualifiedType()); | ||||||||
589 | |||||||||
590 | for (const auto &I : New->exceptions()) { | ||||||||
591 | CanQualType TypePtr = S.Context.getCanonicalType(I).getUnqualifiedType(); | ||||||||
592 | if (OldTypes.count(TypePtr)) | ||||||||
593 | NewTypes.insert(TypePtr); | ||||||||
594 | else { | ||||||||
595 | Success = false; | ||||||||
596 | break; | ||||||||
597 | } | ||||||||
598 | } | ||||||||
599 | |||||||||
600 | if (Success && OldTypes.size() == NewTypes.size()) | ||||||||
601 | return false; | ||||||||
602 | } | ||||||||
603 | |||||||||
604 | // As a special compatibility feature, under C++0x we accept no spec and | ||||||||
605 | // throw(std::bad_alloc) as equivalent for operator new and operator new[]. | ||||||||
606 | // This is because the implicit declaration changed, but old code would break. | ||||||||
607 | if (S.getLangOpts().CPlusPlus11 && IsOperatorNew) { | ||||||||
608 | const FunctionProtoType *WithExceptions = nullptr; | ||||||||
609 | if (OldEST == EST_None && NewEST == EST_Dynamic) | ||||||||
610 | WithExceptions = New; | ||||||||
611 | else if (OldEST == EST_Dynamic && NewEST == EST_None) | ||||||||
612 | WithExceptions = Old; | ||||||||
613 | if (WithExceptions && WithExceptions->getNumExceptions() == 1) { | ||||||||
614 | // One has no spec, the other throw(something). If that something is | ||||||||
615 | // std::bad_alloc, all conditions are met. | ||||||||
616 | QualType Exception = *WithExceptions->exception_begin(); | ||||||||
617 | if (CXXRecordDecl *ExRecord = Exception->getAsCXXRecordDecl()) { | ||||||||
618 | IdentifierInfo* Name = ExRecord->getIdentifier(); | ||||||||
619 | if (Name && Name->getName() == "bad_alloc") { | ||||||||
620 | // It's called bad_alloc, but is it in std? | ||||||||
621 | if (ExRecord->isInStdNamespace()) { | ||||||||
622 | return false; | ||||||||
623 | } | ||||||||
624 | } | ||||||||
625 | } | ||||||||
626 | } | ||||||||
627 | } | ||||||||
628 | |||||||||
629 | // If the caller wants to handle the case that the new function is | ||||||||
630 | // incompatible due to a missing exception specification, let it. | ||||||||
631 | if (MissingExceptionSpecification && OldEST != EST_None && | ||||||||
632 | NewEST == EST_None) { | ||||||||
633 | // The old type has an exception specification of some sort, but | ||||||||
634 | // the new type does not. | ||||||||
635 | *MissingExceptionSpecification = true; | ||||||||
636 | |||||||||
637 | if (MissingEmptyExceptionSpecification && OldCanThrow == CT_Cannot) { | ||||||||
638 | // The old type has a throw() or noexcept(true) exception specification | ||||||||
639 | // and the new type has no exception specification, and the caller asked | ||||||||
640 | // to handle this itself. | ||||||||
641 | *MissingEmptyExceptionSpecification = true; | ||||||||
642 | } | ||||||||
643 | |||||||||
644 | return true; | ||||||||
645 | } | ||||||||
646 | |||||||||
647 | S.Diag(NewLoc, DiagID); | ||||||||
648 | if (NoteID.getDiagID() != 0 && OldLoc.isValid()) | ||||||||
649 | S.Diag(OldLoc, NoteID); | ||||||||
650 | return true; | ||||||||
651 | } | ||||||||
652 | |||||||||
653 | bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, | ||||||||
654 | const PartialDiagnostic &NoteID, | ||||||||
655 | const FunctionProtoType *Old, | ||||||||
656 | SourceLocation OldLoc, | ||||||||
657 | const FunctionProtoType *New, | ||||||||
658 | SourceLocation NewLoc) { | ||||||||
659 | if (!getLangOpts().CXXExceptions) | ||||||||
660 | return false; | ||||||||
661 | return CheckEquivalentExceptionSpecImpl(*this, DiagID, NoteID, Old, OldLoc, | ||||||||
662 | New, NewLoc); | ||||||||
663 | } | ||||||||
664 | |||||||||
665 | bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) { | ||||||||
666 | // [except.handle]p3: | ||||||||
667 | // A handler is a match for an exception object of type E if: | ||||||||
668 | |||||||||
669 | // HandlerType must be ExceptionType or derived from it, or pointer or | ||||||||
670 | // reference to such types. | ||||||||
671 | const ReferenceType *RefTy = HandlerType->getAs<ReferenceType>(); | ||||||||
672 | if (RefTy) | ||||||||
673 | HandlerType = RefTy->getPointeeType(); | ||||||||
674 | |||||||||
675 | // -- the handler is of type cv T or cv T& and E and T are the same type | ||||||||
676 | if (Context.hasSameUnqualifiedType(ExceptionType, HandlerType)) | ||||||||
677 | return true; | ||||||||
678 | |||||||||
679 | // FIXME: ObjC pointer types? | ||||||||
680 | if (HandlerType->isPointerType() || HandlerType->isMemberPointerType()) { | ||||||||
681 | if (RefTy && (!HandlerType.isConstQualified() || | ||||||||
682 | HandlerType.isVolatileQualified())) | ||||||||
683 | return false; | ||||||||
684 | |||||||||
685 | // -- the handler is of type cv T or const T& where T is a pointer or | ||||||||
686 | // pointer to member type and E is std::nullptr_t | ||||||||
687 | if (ExceptionType->isNullPtrType()) | ||||||||
688 | return true; | ||||||||
689 | |||||||||
690 | // -- the handler is of type cv T or const T& where T is a pointer or | ||||||||
691 | // pointer to member type and E is a pointer or pointer to member type | ||||||||
692 | // that can be converted to T by one or more of | ||||||||
693 | // -- a qualification conversion | ||||||||
694 | // -- a function pointer conversion | ||||||||
695 | bool LifetimeConv; | ||||||||
696 | QualType Result; | ||||||||
697 | // FIXME: Should we treat the exception as catchable if a lifetime | ||||||||
698 | // conversion is required? | ||||||||
699 | if (IsQualificationConversion(ExceptionType, HandlerType, false, | ||||||||
700 | LifetimeConv) || | ||||||||
701 | IsFunctionConversion(ExceptionType, HandlerType, Result)) | ||||||||
702 | return true; | ||||||||
703 | |||||||||
704 | // -- a standard pointer conversion [...] | ||||||||
705 | if (!ExceptionType->isPointerType() || !HandlerType->isPointerType()) | ||||||||
706 | return false; | ||||||||
707 | |||||||||
708 | // Handle the "qualification conversion" portion. | ||||||||
709 | Qualifiers EQuals, HQuals; | ||||||||
710 | ExceptionType = Context.getUnqualifiedArrayType( | ||||||||
711 | ExceptionType->getPointeeType(), EQuals); | ||||||||
712 | HandlerType = Context.getUnqualifiedArrayType( | ||||||||
713 | HandlerType->getPointeeType(), HQuals); | ||||||||
714 | if (!HQuals.compatiblyIncludes(EQuals)) | ||||||||
715 | return false; | ||||||||
716 | |||||||||
717 | if (HandlerType->isVoidType() && ExceptionType->isObjectType()) | ||||||||
718 | return true; | ||||||||
719 | |||||||||
720 | // The only remaining case is a derived-to-base conversion. | ||||||||
721 | } | ||||||||
722 | |||||||||
723 | // -- the handler is of type cg T or cv T& and T is an unambiguous public | ||||||||
724 | // base class of E | ||||||||
725 | if (!ExceptionType->isRecordType() || !HandlerType->isRecordType()) | ||||||||
726 | return false; | ||||||||
727 | CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, | ||||||||
728 | /*DetectVirtual=*/false); | ||||||||
729 | if (!IsDerivedFrom(SourceLocation(), ExceptionType, HandlerType, Paths) || | ||||||||
730 | Paths.isAmbiguous(Context.getCanonicalType(HandlerType))) | ||||||||
731 | return false; | ||||||||
732 | |||||||||
733 | // Do this check from a context without privileges. | ||||||||
734 | switch (CheckBaseClassAccess(SourceLocation(), HandlerType, ExceptionType, | ||||||||
735 | Paths.front(), | ||||||||
736 | /*Diagnostic*/ 0, | ||||||||
737 | /*ForceCheck*/ true, | ||||||||
738 | /*ForceUnprivileged*/ true)) { | ||||||||
739 | case AR_accessible: return true; | ||||||||
740 | case AR_inaccessible: return false; | ||||||||
741 | case AR_dependent: | ||||||||
742 | llvm_unreachable("access check dependent for unprivileged context")::llvm::llvm_unreachable_internal("access check dependent for unprivileged context" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 742); | ||||||||
743 | case AR_delayed: | ||||||||
744 | llvm_unreachable("access check delayed in non-declaration")::llvm::llvm_unreachable_internal("access check delayed in non-declaration" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 744); | ||||||||
745 | } | ||||||||
746 | llvm_unreachable("unexpected access check result")::llvm::llvm_unreachable_internal("unexpected access check result" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 746); | ||||||||
747 | } | ||||||||
748 | |||||||||
749 | /// CheckExceptionSpecSubset - Check whether the second function type's | ||||||||
750 | /// exception specification is a subset (or equivalent) of the first function | ||||||||
751 | /// type. This is used by override and pointer assignment checks. | ||||||||
752 | bool Sema::CheckExceptionSpecSubset(const PartialDiagnostic &DiagID, | ||||||||
753 | const PartialDiagnostic &NestedDiagID, | ||||||||
754 | const PartialDiagnostic &NoteID, | ||||||||
755 | const PartialDiagnostic &NoThrowDiagID, | ||||||||
756 | const FunctionProtoType *Superset, | ||||||||
757 | SourceLocation SuperLoc, | ||||||||
758 | const FunctionProtoType *Subset, | ||||||||
759 | SourceLocation SubLoc) { | ||||||||
760 | |||||||||
761 | // Just auto-succeed under -fno-exceptions. | ||||||||
762 | if (!getLangOpts().CXXExceptions) | ||||||||
763 | return false; | ||||||||
764 | |||||||||
765 | // FIXME: As usual, we could be more specific in our error messages, but | ||||||||
766 | // that better waits until we've got types with source locations. | ||||||||
767 | |||||||||
768 | if (!SubLoc.isValid()) | ||||||||
769 | SubLoc = SuperLoc; | ||||||||
770 | |||||||||
771 | // Resolve the exception specifications, if needed. | ||||||||
772 | Superset = ResolveExceptionSpec(SuperLoc, Superset); | ||||||||
773 | if (!Superset) | ||||||||
774 | return false; | ||||||||
775 | Subset = ResolveExceptionSpec(SubLoc, Subset); | ||||||||
776 | if (!Subset) | ||||||||
777 | return false; | ||||||||
778 | |||||||||
779 | ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType(); | ||||||||
780 | ExceptionSpecificationType SubEST = Subset->getExceptionSpecType(); | ||||||||
781 | assert(!isUnresolvedExceptionSpec(SuperEST) &&((!isUnresolvedExceptionSpec(SuperEST) && !isUnresolvedExceptionSpec (SubEST) && "Shouldn't see unknown exception specifications here" ) ? static_cast<void> (0) : __assert_fail ("!isUnresolvedExceptionSpec(SuperEST) && !isUnresolvedExceptionSpec(SubEST) && \"Shouldn't see unknown exception specifications here\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 783, __PRETTY_FUNCTION__)) | ||||||||
782 | !isUnresolvedExceptionSpec(SubEST) &&((!isUnresolvedExceptionSpec(SuperEST) && !isUnresolvedExceptionSpec (SubEST) && "Shouldn't see unknown exception specifications here" ) ? static_cast<void> (0) : __assert_fail ("!isUnresolvedExceptionSpec(SuperEST) && !isUnresolvedExceptionSpec(SubEST) && \"Shouldn't see unknown exception specifications here\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 783, __PRETTY_FUNCTION__)) | ||||||||
783 | "Shouldn't see unknown exception specifications here")((!isUnresolvedExceptionSpec(SuperEST) && !isUnresolvedExceptionSpec (SubEST) && "Shouldn't see unknown exception specifications here" ) ? static_cast<void> (0) : __assert_fail ("!isUnresolvedExceptionSpec(SuperEST) && !isUnresolvedExceptionSpec(SubEST) && \"Shouldn't see unknown exception specifications here\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 783, __PRETTY_FUNCTION__)); | ||||||||
784 | |||||||||
785 | // If there are dependent noexcept specs, assume everything is fine. Unlike | ||||||||
786 | // with the equivalency check, this is safe in this case, because we don't | ||||||||
787 | // want to merge declarations. Checks after instantiation will catch any | ||||||||
788 | // omissions we make here. | ||||||||
789 | if (SuperEST == EST_DependentNoexcept || SubEST == EST_DependentNoexcept) | ||||||||
790 | return false; | ||||||||
791 | |||||||||
792 | CanThrowResult SuperCanThrow = Superset->canThrow(); | ||||||||
793 | CanThrowResult SubCanThrow = Subset->canThrow(); | ||||||||
794 | |||||||||
795 | // If the superset contains everything or the subset contains nothing, we're | ||||||||
796 | // done. | ||||||||
797 | if ((SuperCanThrow == CT_Can && SuperEST != EST_Dynamic) || | ||||||||
798 | SubCanThrow == CT_Cannot) | ||||||||
799 | return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc, | ||||||||
800 | Subset, SubLoc); | ||||||||
801 | |||||||||
802 | // Allow __declspec(nothrow) to be missing on redeclaration as an extension in | ||||||||
803 | // some cases. | ||||||||
804 | if (NoThrowDiagID.getDiagID() != 0 && SubCanThrow == CT_Can && | ||||||||
805 | SuperCanThrow == CT_Cannot && SuperEST == EST_NoThrow) { | ||||||||
806 | Diag(SubLoc, NoThrowDiagID); | ||||||||
807 | if (NoteID.getDiagID() != 0) | ||||||||
808 | Diag(SuperLoc, NoteID); | ||||||||
809 | return true; | ||||||||
810 | } | ||||||||
811 | |||||||||
812 | // If the subset contains everything or the superset contains nothing, we've | ||||||||
813 | // failed. | ||||||||
814 | if ((SubCanThrow == CT_Can && SubEST != EST_Dynamic) || | ||||||||
815 | SuperCanThrow == CT_Cannot) { | ||||||||
816 | Diag(SubLoc, DiagID); | ||||||||
817 | if (NoteID.getDiagID() != 0) | ||||||||
818 | Diag(SuperLoc, NoteID); | ||||||||
819 | return true; | ||||||||
820 | } | ||||||||
821 | |||||||||
822 | assert(SuperEST == EST_Dynamic && SubEST == EST_Dynamic &&((SuperEST == EST_Dynamic && SubEST == EST_Dynamic && "Exception spec subset: non-dynamic case slipped through.") ? static_cast<void> (0) : __assert_fail ("SuperEST == EST_Dynamic && SubEST == EST_Dynamic && \"Exception spec subset: non-dynamic case slipped through.\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 823, __PRETTY_FUNCTION__)) | ||||||||
823 | "Exception spec subset: non-dynamic case slipped through.")((SuperEST == EST_Dynamic && SubEST == EST_Dynamic && "Exception spec subset: non-dynamic case slipped through.") ? static_cast<void> (0) : __assert_fail ("SuperEST == EST_Dynamic && SubEST == EST_Dynamic && \"Exception spec subset: non-dynamic case slipped through.\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 823, __PRETTY_FUNCTION__)); | ||||||||
824 | |||||||||
825 | // Neither contains everything or nothing. Do a proper comparison. | ||||||||
826 | for (QualType SubI : Subset->exceptions()) { | ||||||||
827 | if (const ReferenceType *RefTy = SubI->getAs<ReferenceType>()) | ||||||||
828 | SubI = RefTy->getPointeeType(); | ||||||||
829 | |||||||||
830 | // Make sure it's in the superset. | ||||||||
831 | bool Contained = false; | ||||||||
832 | for (QualType SuperI : Superset->exceptions()) { | ||||||||
833 | // [except.spec]p5: | ||||||||
834 | // the target entity shall allow at least the exceptions allowed by the | ||||||||
835 | // source | ||||||||
836 | // | ||||||||
837 | // We interpret this as meaning that a handler for some target type would | ||||||||
838 | // catch an exception of each source type. | ||||||||
839 | if (handlerCanCatch(SuperI, SubI)) { | ||||||||
840 | Contained = true; | ||||||||
841 | break; | ||||||||
842 | } | ||||||||
843 | } | ||||||||
844 | if (!Contained) { | ||||||||
845 | Diag(SubLoc, DiagID); | ||||||||
846 | if (NoteID.getDiagID() != 0) | ||||||||
847 | Diag(SuperLoc, NoteID); | ||||||||
848 | return true; | ||||||||
849 | } | ||||||||
850 | } | ||||||||
851 | // We've run half the gauntlet. | ||||||||
852 | return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc, | ||||||||
853 | Subset, SubLoc); | ||||||||
854 | } | ||||||||
855 | |||||||||
856 | static bool | ||||||||
857 | CheckSpecForTypesEquivalent(Sema &S, const PartialDiagnostic &DiagID, | ||||||||
858 | const PartialDiagnostic &NoteID, QualType Target, | ||||||||
859 | SourceLocation TargetLoc, QualType Source, | ||||||||
860 | SourceLocation SourceLoc) { | ||||||||
861 | const FunctionProtoType *TFunc = GetUnderlyingFunction(Target); | ||||||||
862 | if (!TFunc) | ||||||||
863 | return false; | ||||||||
864 | const FunctionProtoType *SFunc = GetUnderlyingFunction(Source); | ||||||||
865 | if (!SFunc) | ||||||||
866 | return false; | ||||||||
867 | |||||||||
868 | return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc, | ||||||||
869 | SFunc, SourceLoc); | ||||||||
870 | } | ||||||||
871 | |||||||||
872 | /// CheckParamExceptionSpec - Check if the parameter and return types of the | ||||||||
873 | /// two functions have equivalent exception specs. This is part of the | ||||||||
874 | /// assignment and override compatibility check. We do not check the parameters | ||||||||
875 | /// of parameter function pointers recursively, as no sane programmer would | ||||||||
876 | /// even be able to write such a function type. | ||||||||
877 | bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &DiagID, | ||||||||
878 | const PartialDiagnostic &NoteID, | ||||||||
879 | const FunctionProtoType *Target, | ||||||||
880 | SourceLocation TargetLoc, | ||||||||
881 | const FunctionProtoType *Source, | ||||||||
882 | SourceLocation SourceLoc) { | ||||||||
883 | auto RetDiag = DiagID; | ||||||||
884 | RetDiag << 0; | ||||||||
885 | if (CheckSpecForTypesEquivalent( | ||||||||
886 | *this, RetDiag, PDiag(), | ||||||||
887 | Target->getReturnType(), TargetLoc, Source->getReturnType(), | ||||||||
888 | SourceLoc)) | ||||||||
889 | return true; | ||||||||
890 | |||||||||
891 | // We shouldn't even be testing this unless the arguments are otherwise | ||||||||
892 | // compatible. | ||||||||
893 | assert(Target->getNumParams() == Source->getNumParams() &&((Target->getNumParams() == Source->getNumParams() && "Functions have different argument counts.") ? static_cast< void> (0) : __assert_fail ("Target->getNumParams() == Source->getNumParams() && \"Functions have different argument counts.\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 894, __PRETTY_FUNCTION__)) | ||||||||
894 | "Functions have different argument counts.")((Target->getNumParams() == Source->getNumParams() && "Functions have different argument counts.") ? static_cast< void> (0) : __assert_fail ("Target->getNumParams() == Source->getNumParams() && \"Functions have different argument counts.\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 894, __PRETTY_FUNCTION__)); | ||||||||
895 | for (unsigned i = 0, E = Target->getNumParams(); i != E; ++i) { | ||||||||
896 | auto ParamDiag = DiagID; | ||||||||
897 | ParamDiag << 1; | ||||||||
898 | if (CheckSpecForTypesEquivalent( | ||||||||
899 | *this, ParamDiag, PDiag(), | ||||||||
900 | Target->getParamType(i), TargetLoc, Source->getParamType(i), | ||||||||
901 | SourceLoc)) | ||||||||
902 | return true; | ||||||||
903 | } | ||||||||
904 | return false; | ||||||||
905 | } | ||||||||
906 | |||||||||
907 | bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) { | ||||||||
908 | // First we check for applicability. | ||||||||
909 | // Target type must be a function, function pointer or function reference. | ||||||||
910 | const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType); | ||||||||
911 | if (!ToFunc || ToFunc->hasDependentExceptionSpec()) | ||||||||
912 | return false; | ||||||||
913 | |||||||||
914 | // SourceType must be a function or function pointer. | ||||||||
915 | const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType()); | ||||||||
916 | if (!FromFunc || FromFunc->hasDependentExceptionSpec()) | ||||||||
917 | return false; | ||||||||
918 | |||||||||
919 | unsigned DiagID = diag::err_incompatible_exception_specs; | ||||||||
920 | unsigned NestedDiagID = diag::err_deep_exception_specs_differ; | ||||||||
921 | // This is not an error in C++17 onwards, unless the noexceptness doesn't | ||||||||
922 | // match, but in that case we have a full-on type mismatch, not just a | ||||||||
923 | // type sugar mismatch. | ||||||||
924 | if (getLangOpts().CPlusPlus17) { | ||||||||
925 | DiagID = diag::warn_incompatible_exception_specs; | ||||||||
926 | NestedDiagID = diag::warn_deep_exception_specs_differ; | ||||||||
927 | } | ||||||||
928 | |||||||||
929 | // Now we've got the correct types on both sides, check their compatibility. | ||||||||
930 | // This means that the source of the conversion can only throw a subset of | ||||||||
931 | // the exceptions of the target, and any exception specs on arguments or | ||||||||
932 | // return types must be equivalent. | ||||||||
933 | // | ||||||||
934 | // FIXME: If there is a nested dependent exception specification, we should | ||||||||
935 | // not be checking it here. This is fine: | ||||||||
936 | // template<typename T> void f() { | ||||||||
937 | // void (*p)(void (*) throw(T)); | ||||||||
938 | // void (*q)(void (*) throw(int)) = p; | ||||||||
939 | // } | ||||||||
940 | // ... because it might be instantiated with T=int. | ||||||||
941 | return CheckExceptionSpecSubset( | ||||||||
942 | PDiag(DiagID), PDiag(NestedDiagID), PDiag(), PDiag(), ToFunc, | ||||||||
943 | From->getSourceRange().getBegin(), FromFunc, SourceLocation()) && | ||||||||
944 | !getLangOpts().CPlusPlus17; | ||||||||
945 | } | ||||||||
946 | |||||||||
947 | bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, | ||||||||
948 | const CXXMethodDecl *Old) { | ||||||||
949 | // If the new exception specification hasn't been parsed yet, skip the check. | ||||||||
950 | // We'll get called again once it's been parsed. | ||||||||
951 | if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() == | ||||||||
952 | EST_Unparsed) | ||||||||
953 | return false; | ||||||||
954 | |||||||||
955 | // Don't check uninstantiated template destructors at all. We can only | ||||||||
956 | // synthesize correct specs after the template is instantiated. | ||||||||
957 | if (isa<CXXDestructorDecl>(New) && New->getParent()->isDependentType()) | ||||||||
958 | return false; | ||||||||
959 | |||||||||
960 | // If the old exception specification hasn't been parsed yet, or the new | ||||||||
961 | // exception specification can't be computed yet, remember that we need to | ||||||||
962 | // perform this check when we get to the end of the outermost | ||||||||
963 | // lexically-surrounding class. | ||||||||
964 | if (exceptionSpecNotKnownYet(Old) || exceptionSpecNotKnownYet(New)) { | ||||||||
965 | DelayedOverridingExceptionSpecChecks.push_back({New, Old}); | ||||||||
966 | return false; | ||||||||
967 | } | ||||||||
968 | |||||||||
969 | unsigned DiagID = diag::err_override_exception_spec; | ||||||||
970 | if (getLangOpts().MSVCCompat) | ||||||||
971 | DiagID = diag::ext_override_exception_spec; | ||||||||
972 | return CheckExceptionSpecSubset(PDiag(DiagID), | ||||||||
973 | PDiag(diag::err_deep_exception_specs_differ), | ||||||||
974 | PDiag(diag::note_overridden_virtual_function), | ||||||||
975 | PDiag(diag::ext_override_exception_spec), | ||||||||
976 | Old->getType()->castAs<FunctionProtoType>(), | ||||||||
977 | Old->getLocation(), | ||||||||
978 | New->getType()->castAs<FunctionProtoType>(), | ||||||||
979 | New->getLocation()); | ||||||||
980 | } | ||||||||
981 | |||||||||
982 | static CanThrowResult canSubStmtsThrow(Sema &Self, const Stmt *S) { | ||||||||
983 | CanThrowResult R = CT_Cannot; | ||||||||
984 | for (const Stmt *SubStmt : S->children()) { | ||||||||
985 | if (!SubStmt) | ||||||||
986 | continue; | ||||||||
987 | R = mergeCanThrow(R, Self.canThrow(SubStmt)); | ||||||||
988 | if (R == CT_Can) | ||||||||
989 | break; | ||||||||
990 | } | ||||||||
991 | return R; | ||||||||
992 | } | ||||||||
993 | |||||||||
994 | /// Determine whether the callee of a particular function call can throw. | ||||||||
995 | /// E and D are both optional, but at least one of E and Loc must be specified. | ||||||||
996 | static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D, | ||||||||
997 | SourceLocation Loc = SourceLocation()) { | ||||||||
998 | // As an extension, we assume that __attribute__((nothrow)) functions don't | ||||||||
999 | // throw. | ||||||||
1000 | if (D
| ||||||||
1001 | return CT_Cannot; | ||||||||
1002 | |||||||||
1003 | QualType T; | ||||||||
1004 | |||||||||
1005 | // In C++1z, just look at the function type of the callee. | ||||||||
1006 | if (S.getLangOpts().CPlusPlus17 && E && isa<CallExpr>(E)) { | ||||||||
1007 | E = cast<CallExpr>(E)->getCallee(); | ||||||||
1008 | T = E->getType(); | ||||||||
1009 | if (T->isSpecificPlaceholderType(BuiltinType::BoundMember)) { | ||||||||
1010 | // Sadly we don't preserve the actual type as part of the "bound member" | ||||||||
1011 | // placeholder, so we need to reconstruct it. | ||||||||
1012 | E = E->IgnoreParenImpCasts(); | ||||||||
1013 | |||||||||
1014 | // Could be a call to a pointer-to-member or a plain member access. | ||||||||
1015 | if (auto *Op = dyn_cast<BinaryOperator>(E)) { | ||||||||
1016 | assert(Op->getOpcode() == BO_PtrMemD || Op->getOpcode() == BO_PtrMemI)((Op->getOpcode() == BO_PtrMemD || Op->getOpcode() == BO_PtrMemI ) ? static_cast<void> (0) : __assert_fail ("Op->getOpcode() == BO_PtrMemD || Op->getOpcode() == BO_PtrMemI" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 1016, __PRETTY_FUNCTION__)); | ||||||||
1017 | T = Op->getRHS()->getType() | ||||||||
1018 | ->castAs<MemberPointerType>()->getPointeeType(); | ||||||||
1019 | } else { | ||||||||
1020 | T = cast<MemberExpr>(E)->getMemberDecl()->getType(); | ||||||||
1021 | } | ||||||||
1022 | } | ||||||||
1023 | } else if (const ValueDecl *VD
| ||||||||
1024 | T = VD->getType(); | ||||||||
1025 | else | ||||||||
1026 | // If we have no clue what we're calling, assume the worst. | ||||||||
1027 | return CT_Can; | ||||||||
1028 | |||||||||
1029 | const FunctionProtoType *FT; | ||||||||
1030 | if ((FT = T->getAs<FunctionProtoType>())) { | ||||||||
1031 | } else if (const PointerType *PT
| ||||||||
1032 | FT = PT->getPointeeType()->getAs<FunctionProtoType>(); | ||||||||
1033 | else if (const ReferenceType *RT
| ||||||||
1034 | FT = RT->getPointeeType()->getAs<FunctionProtoType>(); | ||||||||
1035 | else if (const MemberPointerType *MT
| ||||||||
1036 | FT = MT->getPointeeType()->getAs<FunctionProtoType>(); | ||||||||
1037 | else if (const BlockPointerType *BT
| ||||||||
1038 | FT = BT->getPointeeType()->getAs<FunctionProtoType>(); | ||||||||
1039 | |||||||||
1040 | if (!FT
| ||||||||
1041 | return CT_Can; | ||||||||
1042 | |||||||||
1043 | FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT); | ||||||||
| |||||||||
1044 | if (!FT) | ||||||||
1045 | return CT_Can; | ||||||||
1046 | |||||||||
1047 | return FT->canThrow(); | ||||||||
1048 | } | ||||||||
1049 | |||||||||
1050 | static CanThrowResult canVarDeclThrow(Sema &Self, const VarDecl *VD) { | ||||||||
1051 | CanThrowResult CT = CT_Cannot; | ||||||||
1052 | |||||||||
1053 | // Initialization might throw. | ||||||||
1054 | if (!VD->isUsableInConstantExpressions(Self.Context)) | ||||||||
1055 | if (const Expr *Init = VD->getInit()) | ||||||||
1056 | CT = mergeCanThrow(CT, Self.canThrow(Init)); | ||||||||
1057 | |||||||||
1058 | // Destructor might throw. | ||||||||
1059 | if (VD->needsDestruction(Self.Context) == QualType::DK_cxx_destructor) { | ||||||||
1060 | if (auto *RD = | ||||||||
1061 | VD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) { | ||||||||
1062 | if (auto *Dtor = RD->getDestructor()) { | ||||||||
1063 | CT = mergeCanThrow( | ||||||||
1064 | CT, canCalleeThrow(Self, nullptr, Dtor, VD->getLocation())); | ||||||||
1065 | } | ||||||||
1066 | } | ||||||||
1067 | } | ||||||||
1068 | |||||||||
1069 | // If this is a decomposition declaration, bindings might throw. | ||||||||
1070 | if (auto *DD
| ||||||||
1071 | for (auto *B : DD->bindings()) | ||||||||
1072 | if (auto *HD = B->getHoldingVar()) | ||||||||
1073 | CT = mergeCanThrow(CT, canVarDeclThrow(Self, HD)); | ||||||||
1074 | |||||||||
1075 | return CT; | ||||||||
1076 | } | ||||||||
1077 | |||||||||
1078 | static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) { | ||||||||
1079 | if (DC->isTypeDependent()) | ||||||||
1080 | return CT_Dependent; | ||||||||
1081 | |||||||||
1082 | if (!DC->getTypeAsWritten()->isReferenceType()) | ||||||||
1083 | return CT_Cannot; | ||||||||
1084 | |||||||||
1085 | if (DC->getSubExpr()->isTypeDependent()) | ||||||||
1086 | return CT_Dependent; | ||||||||
1087 | |||||||||
1088 | return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot; | ||||||||
1089 | } | ||||||||
1090 | |||||||||
1091 | static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) { | ||||||||
1092 | if (DC->isTypeOperand()) | ||||||||
1093 | return CT_Cannot; | ||||||||
1094 | |||||||||
1095 | Expr *Op = DC->getExprOperand(); | ||||||||
1096 | if (Op->isTypeDependent()) | ||||||||
1097 | return CT_Dependent; | ||||||||
1098 | |||||||||
1099 | const RecordType *RT = Op->getType()->getAs<RecordType>(); | ||||||||
1100 | if (!RT) | ||||||||
1101 | return CT_Cannot; | ||||||||
1102 | |||||||||
1103 | if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic()) | ||||||||
1104 | return CT_Cannot; | ||||||||
1105 | |||||||||
1106 | if (Op->Classify(S.Context).isPRValue()) | ||||||||
1107 | return CT_Cannot; | ||||||||
1108 | |||||||||
1109 | return CT_Can; | ||||||||
1110 | } | ||||||||
1111 | |||||||||
1112 | CanThrowResult Sema::canThrow(const Stmt *S) { | ||||||||
1113 | // C++ [expr.unary.noexcept]p3: | ||||||||
1114 | // [Can throw] if in a potentially-evaluated context the expression would | ||||||||
1115 | // contain: | ||||||||
1116 | switch (S->getStmtClass()) { | ||||||||
| |||||||||
1117 | case Expr::ConstantExprClass: | ||||||||
1118 | return canThrow(cast<ConstantExpr>(S)->getSubExpr()); | ||||||||
1119 | |||||||||
1120 | case Expr::CXXThrowExprClass: | ||||||||
1121 | // - a potentially evaluated throw-expression | ||||||||
1122 | return CT_Can; | ||||||||
1123 | |||||||||
1124 | case Expr::CXXDynamicCastExprClass: { | ||||||||
1125 | // - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v), | ||||||||
1126 | // where T is a reference type, that requires a run-time check | ||||||||
1127 | auto *CE = cast<CXXDynamicCastExpr>(S); | ||||||||
1128 | // FIXME: Properly determine whether a variably-modified type can throw. | ||||||||
1129 | if (CE->getType()->isVariablyModifiedType()) | ||||||||
1130 | return CT_Can; | ||||||||
1131 | CanThrowResult CT = canDynamicCastThrow(CE); | ||||||||
1132 | if (CT == CT_Can) | ||||||||
1133 | return CT; | ||||||||
1134 | return mergeCanThrow(CT, canSubStmtsThrow(*this, CE)); | ||||||||
1135 | } | ||||||||
1136 | |||||||||
1137 | case Expr::CXXTypeidExprClass: | ||||||||
1138 | // - a potentially evaluated typeid expression applied to a glvalue | ||||||||
1139 | // expression whose type is a polymorphic class type | ||||||||
1140 | return canTypeidThrow(*this, cast<CXXTypeidExpr>(S)); | ||||||||
1141 | |||||||||
1142 | // - a potentially evaluated call to a function, member function, function | ||||||||
1143 | // pointer, or member function pointer that does not have a non-throwing | ||||||||
1144 | // exception-specification | ||||||||
1145 | case Expr::CallExprClass: | ||||||||
1146 | case Expr::CXXMemberCallExprClass: | ||||||||
1147 | case Expr::CXXOperatorCallExprClass: | ||||||||
1148 | case Expr::UserDefinedLiteralClass: { | ||||||||
1149 | const CallExpr *CE = cast<CallExpr>(S); | ||||||||
1150 | CanThrowResult CT; | ||||||||
1151 | if (CE->isTypeDependent()) | ||||||||
1152 | CT = CT_Dependent; | ||||||||
1153 | else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) | ||||||||
1154 | CT = CT_Cannot; | ||||||||
1155 | else | ||||||||
1156 | CT = canCalleeThrow(*this, CE, CE->getCalleeDecl()); | ||||||||
1157 | if (CT == CT_Can) | ||||||||
1158 | return CT; | ||||||||
1159 | return mergeCanThrow(CT, canSubStmtsThrow(*this, CE)); | ||||||||
1160 | } | ||||||||
1161 | |||||||||
1162 | case Expr::CXXConstructExprClass: | ||||||||
1163 | case Expr::CXXTemporaryObjectExprClass: { | ||||||||
1164 | auto *CE = cast<CXXConstructExpr>(S); | ||||||||
1165 | // FIXME: Properly determine whether a variably-modified type can throw. | ||||||||
1166 | if (CE->getType()->isVariablyModifiedType()) | ||||||||
1167 | return CT_Can; | ||||||||
1168 | CanThrowResult CT = canCalleeThrow(*this, CE, CE->getConstructor()); | ||||||||
1169 | if (CT == CT_Can) | ||||||||
1170 | return CT; | ||||||||
1171 | return mergeCanThrow(CT, canSubStmtsThrow(*this, CE)); | ||||||||
1172 | } | ||||||||
1173 | |||||||||
1174 | case Expr::CXXInheritedCtorInitExprClass: { | ||||||||
1175 | auto *ICIE = cast<CXXInheritedCtorInitExpr>(S); | ||||||||
1176 | return canCalleeThrow(*this, ICIE, ICIE->getConstructor()); | ||||||||
1177 | } | ||||||||
1178 | |||||||||
1179 | case Expr::LambdaExprClass: { | ||||||||
1180 | const LambdaExpr *Lambda = cast<LambdaExpr>(S); | ||||||||
1181 | CanThrowResult CT = CT_Cannot; | ||||||||
1182 | for (LambdaExpr::const_capture_init_iterator | ||||||||
1183 | Cap = Lambda->capture_init_begin(), | ||||||||
1184 | CapEnd = Lambda->capture_init_end(); | ||||||||
1185 | Cap != CapEnd; ++Cap) | ||||||||
1186 | CT = mergeCanThrow(CT, canThrow(*Cap)); | ||||||||
1187 | return CT; | ||||||||
1188 | } | ||||||||
1189 | |||||||||
1190 | case Expr::CXXNewExprClass: { | ||||||||
1191 | auto *NE = cast<CXXNewExpr>(S); | ||||||||
1192 | CanThrowResult CT; | ||||||||
1193 | if (NE->isTypeDependent()) | ||||||||
1194 | CT = CT_Dependent; | ||||||||
1195 | else | ||||||||
1196 | CT = canCalleeThrow(*this, NE, NE->getOperatorNew()); | ||||||||
1197 | if (CT == CT_Can) | ||||||||
1198 | return CT; | ||||||||
1199 | return mergeCanThrow(CT, canSubStmtsThrow(*this, NE)); | ||||||||
1200 | } | ||||||||
1201 | |||||||||
1202 | case Expr::CXXDeleteExprClass: { | ||||||||
1203 | auto *DE = cast<CXXDeleteExpr>(S); | ||||||||
1204 | CanThrowResult CT; | ||||||||
1205 | QualType DTy = DE->getDestroyedType(); | ||||||||
1206 | if (DTy.isNull() || DTy->isDependentType()) { | ||||||||
1207 | CT = CT_Dependent; | ||||||||
1208 | } else { | ||||||||
1209 | CT = canCalleeThrow(*this, DE, DE->getOperatorDelete()); | ||||||||
1210 | if (const RecordType *RT = DTy->getAs<RecordType>()) { | ||||||||
1211 | const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); | ||||||||
1212 | const CXXDestructorDecl *DD = RD->getDestructor(); | ||||||||
1213 | if (DD) | ||||||||
1214 | CT = mergeCanThrow(CT, canCalleeThrow(*this, DE, DD)); | ||||||||
1215 | } | ||||||||
1216 | if (CT == CT_Can) | ||||||||
1217 | return CT; | ||||||||
1218 | } | ||||||||
1219 | return mergeCanThrow(CT, canSubStmtsThrow(*this, DE)); | ||||||||
1220 | } | ||||||||
1221 | |||||||||
1222 | case Expr::CXXBindTemporaryExprClass: { | ||||||||
1223 | auto *BTE = cast<CXXBindTemporaryExpr>(S); | ||||||||
1224 | // The bound temporary has to be destroyed again, which might throw. | ||||||||
1225 | CanThrowResult CT = | ||||||||
1226 | canCalleeThrow(*this, BTE, BTE->getTemporary()->getDestructor()); | ||||||||
1227 | if (CT == CT_Can) | ||||||||
1228 | return CT; | ||||||||
1229 | return mergeCanThrow(CT, canSubStmtsThrow(*this, BTE)); | ||||||||
1230 | } | ||||||||
1231 | |||||||||
1232 | case Expr::PseudoObjectExprClass: { | ||||||||
1233 | auto *POE = cast<PseudoObjectExpr>(S); | ||||||||
1234 | CanThrowResult CT = CT_Cannot; | ||||||||
1235 | for (const Expr *E : POE->semantics()) { | ||||||||
1236 | CT = mergeCanThrow(CT, canThrow(E)); | ||||||||
1237 | if (CT == CT_Can) | ||||||||
1238 | break; | ||||||||
1239 | } | ||||||||
1240 | return CT; | ||||||||
1241 | } | ||||||||
1242 | |||||||||
1243 | // ObjC message sends are like function calls, but never have exception | ||||||||
1244 | // specs. | ||||||||
1245 | case Expr::ObjCMessageExprClass: | ||||||||
1246 | case Expr::ObjCPropertyRefExprClass: | ||||||||
1247 | case Expr::ObjCSubscriptRefExprClass: | ||||||||
1248 | return CT_Can; | ||||||||
1249 | |||||||||
1250 | // All the ObjC literals that are implemented as calls are | ||||||||
1251 | // potentially throwing unless we decide to close off that | ||||||||
1252 | // possibility. | ||||||||
1253 | case Expr::ObjCArrayLiteralClass: | ||||||||
1254 | case Expr::ObjCDictionaryLiteralClass: | ||||||||
1255 | case Expr::ObjCBoxedExprClass: | ||||||||
1256 | return CT_Can; | ||||||||
1257 | |||||||||
1258 | // Many other things have subexpressions, so we have to test those. | ||||||||
1259 | // Some are simple: | ||||||||
1260 | case Expr::CoawaitExprClass: | ||||||||
1261 | case Expr::ConditionalOperatorClass: | ||||||||
1262 | case Expr::CoyieldExprClass: | ||||||||
1263 | case Expr::CXXRewrittenBinaryOperatorClass: | ||||||||
1264 | case Expr::CXXStdInitializerListExprClass: | ||||||||
1265 | case Expr::DesignatedInitExprClass: | ||||||||
1266 | case Expr::DesignatedInitUpdateExprClass: | ||||||||
1267 | case Expr::ExprWithCleanupsClass: | ||||||||
1268 | case Expr::ExtVectorElementExprClass: | ||||||||
1269 | case Expr::InitListExprClass: | ||||||||
1270 | case Expr::ArrayInitLoopExprClass: | ||||||||
1271 | case Expr::MemberExprClass: | ||||||||
1272 | case Expr::ObjCIsaExprClass: | ||||||||
1273 | case Expr::ObjCIvarRefExprClass: | ||||||||
1274 | case Expr::ParenExprClass: | ||||||||
1275 | case Expr::ParenListExprClass: | ||||||||
1276 | case Expr::ShuffleVectorExprClass: | ||||||||
1277 | case Expr::StmtExprClass: | ||||||||
1278 | case Expr::ConvertVectorExprClass: | ||||||||
1279 | case Expr::VAArgExprClass: | ||||||||
1280 | return canSubStmtsThrow(*this, S); | ||||||||
1281 | |||||||||
1282 | case Expr::CompoundLiteralExprClass: | ||||||||
1283 | case Expr::CXXConstCastExprClass: | ||||||||
1284 | case Expr::CXXReinterpretCastExprClass: | ||||||||
1285 | case Expr::BuiltinBitCastExprClass: | ||||||||
1286 | // FIXME: Properly determine whether a variably-modified type can throw. | ||||||||
1287 | if (cast<Expr>(S)->getType()->isVariablyModifiedType()) | ||||||||
1288 | return CT_Can; | ||||||||
1289 | return canSubStmtsThrow(*this, S); | ||||||||
1290 | |||||||||
1291 | // Some might be dependent for other reasons. | ||||||||
1292 | case Expr::ArraySubscriptExprClass: | ||||||||
1293 | case Expr::OMPArraySectionExprClass: | ||||||||
1294 | case Expr::BinaryOperatorClass: | ||||||||
1295 | case Expr::DependentCoawaitExprClass: | ||||||||
1296 | case Expr::CompoundAssignOperatorClass: | ||||||||
1297 | case Expr::CStyleCastExprClass: | ||||||||
1298 | case Expr::CXXStaticCastExprClass: | ||||||||
1299 | case Expr::CXXFunctionalCastExprClass: | ||||||||
1300 | case Expr::ImplicitCastExprClass: | ||||||||
1301 | case Expr::MaterializeTemporaryExprClass: | ||||||||
1302 | case Expr::UnaryOperatorClass: { | ||||||||
1303 | // FIXME: Properly determine whether a variably-modified type can throw. | ||||||||
1304 | if (auto *CE = dyn_cast<CastExpr>(S)) | ||||||||
1305 | if (CE->getType()->isVariablyModifiedType()) | ||||||||
1306 | return CT_Can; | ||||||||
1307 | CanThrowResult CT = | ||||||||
1308 | cast<Expr>(S)->isTypeDependent() ? CT_Dependent : CT_Cannot; | ||||||||
1309 | return mergeCanThrow(CT, canSubStmtsThrow(*this, S)); | ||||||||
1310 | } | ||||||||
1311 | |||||||||
1312 | case Expr::CXXDefaultArgExprClass: | ||||||||
1313 | return canThrow(cast<CXXDefaultArgExpr>(S)->getExpr()); | ||||||||
1314 | |||||||||
1315 | case Expr::CXXDefaultInitExprClass: | ||||||||
1316 | return canThrow(cast<CXXDefaultInitExpr>(S)->getExpr()); | ||||||||
1317 | |||||||||
1318 | case Expr::ChooseExprClass: { | ||||||||
1319 | auto *CE = cast<ChooseExpr>(S); | ||||||||
1320 | if (CE->isTypeDependent() || CE->isValueDependent()) | ||||||||
1321 | return CT_Dependent; | ||||||||
1322 | return canThrow(CE->getChosenSubExpr()); | ||||||||
1323 | } | ||||||||
1324 | |||||||||
1325 | case Expr::GenericSelectionExprClass: | ||||||||
1326 | if (cast<GenericSelectionExpr>(S)->isResultDependent()) | ||||||||
1327 | return CT_Dependent; | ||||||||
1328 | return canThrow(cast<GenericSelectionExpr>(S)->getResultExpr()); | ||||||||
1329 | |||||||||
1330 | // Some expressions are always dependent. | ||||||||
1331 | case Expr::CXXDependentScopeMemberExprClass: | ||||||||
1332 | case Expr::CXXUnresolvedConstructExprClass: | ||||||||
1333 | case Expr::DependentScopeDeclRefExprClass: | ||||||||
1334 | case Expr::CXXFoldExprClass: | ||||||||
1335 | return CT_Dependent; | ||||||||
1336 | |||||||||
1337 | case Expr::AsTypeExprClass: | ||||||||
1338 | case Expr::BinaryConditionalOperatorClass: | ||||||||
1339 | case Expr::BlockExprClass: | ||||||||
1340 | case Expr::CUDAKernelCallExprClass: | ||||||||
1341 | case Expr::DeclRefExprClass: | ||||||||
1342 | case Expr::ObjCBridgedCastExprClass: | ||||||||
1343 | case Expr::ObjCIndirectCopyRestoreExprClass: | ||||||||
1344 | case Expr::ObjCProtocolExprClass: | ||||||||
1345 | case Expr::ObjCSelectorExprClass: | ||||||||
1346 | case Expr::ObjCAvailabilityCheckExprClass: | ||||||||
1347 | case Expr::OffsetOfExprClass: | ||||||||
1348 | case Expr::PackExpansionExprClass: | ||||||||
1349 | case Expr::SubstNonTypeTemplateParmExprClass: | ||||||||
1350 | case Expr::SubstNonTypeTemplateParmPackExprClass: | ||||||||
1351 | case Expr::FunctionParmPackExprClass: | ||||||||
1352 | case Expr::UnaryExprOrTypeTraitExprClass: | ||||||||
1353 | case Expr::UnresolvedLookupExprClass: | ||||||||
1354 | case Expr::UnresolvedMemberExprClass: | ||||||||
1355 | case Expr::TypoExprClass: | ||||||||
1356 | // FIXME: Many of the above can throw. | ||||||||
1357 | return CT_Cannot; | ||||||||
1358 | |||||||||
1359 | case Expr::AddrLabelExprClass: | ||||||||
1360 | case Expr::ArrayTypeTraitExprClass: | ||||||||
1361 | case Expr::AtomicExprClass: | ||||||||
1362 | case Expr::TypeTraitExprClass: | ||||||||
1363 | case Expr::CXXBoolLiteralExprClass: | ||||||||
1364 | case Expr::CXXNoexceptExprClass: | ||||||||
1365 | case Expr::CXXNullPtrLiteralExprClass: | ||||||||
1366 | case Expr::CXXPseudoDestructorExprClass: | ||||||||
1367 | case Expr::CXXScalarValueInitExprClass: | ||||||||
1368 | case Expr::CXXThisExprClass: | ||||||||
1369 | case Expr::CXXUuidofExprClass: | ||||||||
1370 | case Expr::CharacterLiteralClass: | ||||||||
1371 | case Expr::ExpressionTraitExprClass: | ||||||||
1372 | case Expr::FloatingLiteralClass: | ||||||||
1373 | case Expr::GNUNullExprClass: | ||||||||
1374 | case Expr::ImaginaryLiteralClass: | ||||||||
1375 | case Expr::ImplicitValueInitExprClass: | ||||||||
1376 | case Expr::IntegerLiteralClass: | ||||||||
1377 | case Expr::FixedPointLiteralClass: | ||||||||
1378 | case Expr::ArrayInitIndexExprClass: | ||||||||
1379 | case Expr::NoInitExprClass: | ||||||||
1380 | case Expr::ObjCEncodeExprClass: | ||||||||
1381 | case Expr::ObjCStringLiteralClass: | ||||||||
1382 | case Expr::ObjCBoolLiteralExprClass: | ||||||||
1383 | case Expr::OpaqueValueExprClass: | ||||||||
1384 | case Expr::PredefinedExprClass: | ||||||||
1385 | case Expr::SizeOfPackExprClass: | ||||||||
1386 | case Expr::StringLiteralClass: | ||||||||
1387 | case Expr::SourceLocExprClass: | ||||||||
1388 | case Expr::ConceptSpecializationExprClass: | ||||||||
1389 | case Expr::RequiresExprClass: | ||||||||
1390 | // These expressions can never throw. | ||||||||
1391 | return CT_Cannot; | ||||||||
1392 | |||||||||
1393 | case Expr::MSPropertyRefExprClass: | ||||||||
1394 | case Expr::MSPropertySubscriptExprClass: | ||||||||
1395 | llvm_unreachable("Invalid class for expression")::llvm::llvm_unreachable_internal("Invalid class for expression" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 1395); | ||||||||
1396 | |||||||||
1397 | // Most statements can throw if any substatement can throw. | ||||||||
1398 | case Stmt::AttributedStmtClass: | ||||||||
1399 | case Stmt::BreakStmtClass: | ||||||||
1400 | case Stmt::CapturedStmtClass: | ||||||||
1401 | case Stmt::CaseStmtClass: | ||||||||
1402 | case Stmt::CompoundStmtClass: | ||||||||
1403 | case Stmt::ContinueStmtClass: | ||||||||
1404 | case Stmt::CoreturnStmtClass: | ||||||||
1405 | case Stmt::CoroutineBodyStmtClass: | ||||||||
1406 | case Stmt::CXXCatchStmtClass: | ||||||||
1407 | case Stmt::CXXForRangeStmtClass: | ||||||||
1408 | case Stmt::DefaultStmtClass: | ||||||||
1409 | case Stmt::DoStmtClass: | ||||||||
1410 | case Stmt::ForStmtClass: | ||||||||
1411 | case Stmt::GCCAsmStmtClass: | ||||||||
1412 | case Stmt::GotoStmtClass: | ||||||||
1413 | case Stmt::IndirectGotoStmtClass: | ||||||||
1414 | case Stmt::LabelStmtClass: | ||||||||
1415 | case Stmt::MSAsmStmtClass: | ||||||||
1416 | case Stmt::MSDependentExistsStmtClass: | ||||||||
1417 | case Stmt::NullStmtClass: | ||||||||
1418 | case Stmt::ObjCAtCatchStmtClass: | ||||||||
1419 | case Stmt::ObjCAtFinallyStmtClass: | ||||||||
1420 | case Stmt::ObjCAtSynchronizedStmtClass: | ||||||||
1421 | case Stmt::ObjCAutoreleasePoolStmtClass: | ||||||||
1422 | case Stmt::ObjCForCollectionStmtClass: | ||||||||
1423 | case Stmt::OMPAtomicDirectiveClass: | ||||||||
1424 | case Stmt::OMPBarrierDirectiveClass: | ||||||||
1425 | case Stmt::OMPCancelDirectiveClass: | ||||||||
1426 | case Stmt::OMPCancellationPointDirectiveClass: | ||||||||
1427 | case Stmt::OMPCriticalDirectiveClass: | ||||||||
1428 | case Stmt::OMPDistributeDirectiveClass: | ||||||||
1429 | case Stmt::OMPDistributeParallelForDirectiveClass: | ||||||||
1430 | case Stmt::OMPDistributeParallelForSimdDirectiveClass: | ||||||||
1431 | case Stmt::OMPDistributeSimdDirectiveClass: | ||||||||
1432 | case Stmt::OMPFlushDirectiveClass: | ||||||||
1433 | case Stmt::OMPDepobjDirectiveClass: | ||||||||
1434 | case Stmt::OMPForDirectiveClass: | ||||||||
1435 | case Stmt::OMPForSimdDirectiveClass: | ||||||||
1436 | case Stmt::OMPMasterDirectiveClass: | ||||||||
1437 | case Stmt::OMPMasterTaskLoopDirectiveClass: | ||||||||
1438 | case Stmt::OMPMasterTaskLoopSimdDirectiveClass: | ||||||||
1439 | case Stmt::OMPOrderedDirectiveClass: | ||||||||
1440 | case Stmt::OMPParallelDirectiveClass: | ||||||||
1441 | case Stmt::OMPParallelForDirectiveClass: | ||||||||
1442 | case Stmt::OMPParallelForSimdDirectiveClass: | ||||||||
1443 | case Stmt::OMPParallelMasterDirectiveClass: | ||||||||
1444 | case Stmt::OMPParallelMasterTaskLoopDirectiveClass: | ||||||||
1445 | case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass: | ||||||||
1446 | case Stmt::OMPParallelSectionsDirectiveClass: | ||||||||
1447 | case Stmt::OMPSectionDirectiveClass: | ||||||||
1448 | case Stmt::OMPSectionsDirectiveClass: | ||||||||
1449 | case Stmt::OMPSimdDirectiveClass: | ||||||||
1450 | case Stmt::OMPSingleDirectiveClass: | ||||||||
1451 | case Stmt::OMPTargetDataDirectiveClass: | ||||||||
1452 | case Stmt::OMPTargetDirectiveClass: | ||||||||
1453 | case Stmt::OMPTargetEnterDataDirectiveClass: | ||||||||
1454 | case Stmt::OMPTargetExitDataDirectiveClass: | ||||||||
1455 | case Stmt::OMPTargetParallelDirectiveClass: | ||||||||
1456 | case Stmt::OMPTargetParallelForDirectiveClass: | ||||||||
1457 | case Stmt::OMPTargetParallelForSimdDirectiveClass: | ||||||||
1458 | case Stmt::OMPTargetSimdDirectiveClass: | ||||||||
1459 | case Stmt::OMPTargetTeamsDirectiveClass: | ||||||||
1460 | case Stmt::OMPTargetTeamsDistributeDirectiveClass: | ||||||||
1461 | case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass: | ||||||||
1462 | case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass: | ||||||||
1463 | case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: | ||||||||
1464 | case Stmt::OMPTargetUpdateDirectiveClass: | ||||||||
1465 | case Stmt::OMPTaskDirectiveClass: | ||||||||
1466 | case Stmt::OMPTaskgroupDirectiveClass: | ||||||||
1467 | case Stmt::OMPTaskLoopDirectiveClass: | ||||||||
1468 | case Stmt::OMPTaskLoopSimdDirectiveClass: | ||||||||
1469 | case Stmt::OMPTaskwaitDirectiveClass: | ||||||||
1470 | case Stmt::OMPTaskyieldDirectiveClass: | ||||||||
1471 | case Stmt::OMPTeamsDirectiveClass: | ||||||||
1472 | case Stmt::OMPTeamsDistributeDirectiveClass: | ||||||||
1473 | case Stmt::OMPTeamsDistributeParallelForDirectiveClass: | ||||||||
1474 | case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass: | ||||||||
1475 | case Stmt::OMPTeamsDistributeSimdDirectiveClass: | ||||||||
1476 | case Stmt::ReturnStmtClass: | ||||||||
1477 | case Stmt::SEHExceptStmtClass: | ||||||||
1478 | case Stmt::SEHFinallyStmtClass: | ||||||||
1479 | case Stmt::SEHLeaveStmtClass: | ||||||||
1480 | case Stmt::SEHTryStmtClass: | ||||||||
1481 | case Stmt::SwitchStmtClass: | ||||||||
1482 | case Stmt::WhileStmtClass: | ||||||||
1483 | return canSubStmtsThrow(*this, S); | ||||||||
1484 | |||||||||
1485 | case Stmt::DeclStmtClass: { | ||||||||
1486 | CanThrowResult CT = CT_Cannot; | ||||||||
1487 | for (const Decl *D : cast<DeclStmt>(S)->decls()) { | ||||||||
1488 | if (auto *VD
| ||||||||
1489 | CT = mergeCanThrow(CT, canVarDeclThrow(*this, VD)); | ||||||||
1490 | |||||||||
1491 | // FIXME: Properly determine whether a variably-modified type can throw. | ||||||||
1492 | if (auto *TND = dyn_cast<TypedefNameDecl>(D)) | ||||||||
1493 | if (TND->getUnderlyingType()->isVariablyModifiedType()) | ||||||||
1494 | return CT_Can; | ||||||||
1495 | if (auto *VD = dyn_cast<ValueDecl>(D)) | ||||||||
1496 | if (VD->getType()->isVariablyModifiedType()) | ||||||||
1497 | return CT_Can; | ||||||||
1498 | } | ||||||||
1499 | return CT; | ||||||||
1500 | } | ||||||||
1501 | |||||||||
1502 | case Stmt::IfStmtClass: { | ||||||||
1503 | auto *IS = cast<IfStmt>(S); | ||||||||
1504 | CanThrowResult CT = CT_Cannot; | ||||||||
1505 | if (const Stmt *Init = IS->getInit()) | ||||||||
1506 | CT = mergeCanThrow(CT, canThrow(Init)); | ||||||||
1507 | if (const Stmt *CondDS = IS->getConditionVariableDeclStmt()) | ||||||||
1508 | CT = mergeCanThrow(CT, canThrow(CondDS)); | ||||||||
1509 | CT = mergeCanThrow(CT, canThrow(IS->getCond())); | ||||||||
1510 | |||||||||
1511 | // For 'if constexpr', consider only the non-discarded case. | ||||||||
1512 | // FIXME: We should add a DiscardedStmt marker to the AST. | ||||||||
1513 | if (Optional<const Stmt *> Case = IS->getNondiscardedCase(Context)) | ||||||||
1514 | return *Case ? mergeCanThrow(CT, canThrow(*Case)) : CT; | ||||||||
1515 | |||||||||
1516 | CanThrowResult Then = canThrow(IS->getThen()); | ||||||||
1517 | CanThrowResult Else = IS->getElse() ? canThrow(IS->getElse()) : CT_Cannot; | ||||||||
1518 | if (Then == Else) | ||||||||
1519 | return mergeCanThrow(CT, Then); | ||||||||
1520 | |||||||||
1521 | // For a dependent 'if constexpr', the result is dependent if it depends on | ||||||||
1522 | // the value of the condition. | ||||||||
1523 | return mergeCanThrow(CT, IS->isConstexpr() ? CT_Dependent | ||||||||
1524 | : mergeCanThrow(Then, Else)); | ||||||||
1525 | } | ||||||||
1526 | |||||||||
1527 | case Stmt::CXXTryStmtClass: { | ||||||||
1528 | auto *TS = cast<CXXTryStmt>(S); | ||||||||
1529 | // try /*...*/ catch (...) { H } can throw only if H can throw. | ||||||||
1530 | // Any other try-catch can throw if any substatement can throw. | ||||||||
1531 | const CXXCatchStmt *FinalHandler = TS->getHandler(TS->getNumHandlers() - 1); | ||||||||
1532 | if (!FinalHandler->getExceptionDecl()) | ||||||||
1533 | return canThrow(FinalHandler->getHandlerBlock()); | ||||||||
1534 | return canSubStmtsThrow(*this, S); | ||||||||
1535 | } | ||||||||
1536 | |||||||||
1537 | case Stmt::ObjCAtThrowStmtClass: | ||||||||
1538 | return CT_Can; | ||||||||
1539 | |||||||||
1540 | case Stmt::ObjCAtTryStmtClass: { | ||||||||
1541 | auto *TS = cast<ObjCAtTryStmt>(S); | ||||||||
1542 | |||||||||
1543 | // @catch(...) need not be last in Objective-C. Walk backwards until we | ||||||||
1544 | // see one or hit the @try. | ||||||||
1545 | CanThrowResult CT = CT_Cannot; | ||||||||
1546 | if (const Stmt *Finally = TS->getFinallyStmt()) | ||||||||
1547 | CT = mergeCanThrow(CT, canThrow(Finally)); | ||||||||
1548 | for (unsigned I = TS->getNumCatchStmts(); I != 0; --I) { | ||||||||
1549 | const ObjCAtCatchStmt *Catch = TS->getCatchStmt(I - 1); | ||||||||
1550 | CT = mergeCanThrow(CT, canThrow(Catch)); | ||||||||
1551 | // If we reach a @catch(...), no earlier exceptions can escape. | ||||||||
1552 | if (Catch->hasEllipsis()) | ||||||||
1553 | return CT; | ||||||||
1554 | } | ||||||||
1555 | |||||||||
1556 | // Didn't find an @catch(...). Exceptions from the @try body can escape. | ||||||||
1557 | return mergeCanThrow(CT, canThrow(TS->getTryBody())); | ||||||||
1558 | } | ||||||||
1559 | |||||||||
1560 | case Stmt::NoStmtClass: | ||||||||
1561 | llvm_unreachable("Invalid class for statement")::llvm::llvm_unreachable_internal("Invalid class for statement" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 1561); | ||||||||
1562 | } | ||||||||
1563 | llvm_unreachable("Bogus StmtClass")::llvm::llvm_unreachable_internal("Bogus StmtClass", "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/lib/Sema/SemaExceptionSpec.cpp" , 1563); | ||||||||
1564 | } | ||||||||
1565 | |||||||||
1566 | } // end namespace clang |
1 | //===- SourceLocation.h - Compact identifier for Source Files ---*- C++ -*-===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | /// \file |
10 | /// Defines the clang::SourceLocation class and associated facilities. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_CLANG_BASIC_SOURCELOCATION_H |
15 | #define LLVM_CLANG_BASIC_SOURCELOCATION_H |
16 | |
17 | #include "clang/Basic/LLVM.h" |
18 | #include "llvm/ADT/StringRef.h" |
19 | #include "llvm/Support/PointerLikeTypeTraits.h" |
20 | #include <cassert> |
21 | #include <cstdint> |
22 | #include <string> |
23 | #include <utility> |
24 | |
25 | namespace llvm { |
26 | |
27 | template <typename T> struct DenseMapInfo; |
28 | |
29 | } // namespace llvm |
30 | |
31 | namespace clang { |
32 | |
33 | class SourceManager; |
34 | |
35 | /// An opaque identifier used by SourceManager which refers to a |
36 | /// source file (MemoryBuffer) along with its \#include path and \#line data. |
37 | /// |
38 | class FileID { |
39 | /// A mostly-opaque identifier, where 0 is "invalid", >0 is |
40 | /// this module, and <-1 is something loaded from another module. |
41 | int ID = 0; |
42 | |
43 | public: |
44 | bool isValid() const { return ID != 0; } |
45 | bool isInvalid() const { return ID == 0; } |
46 | |
47 | bool operator==(const FileID &RHS) const { return ID == RHS.ID; } |
48 | bool operator<(const FileID &RHS) const { return ID < RHS.ID; } |
49 | bool operator<=(const FileID &RHS) const { return ID <= RHS.ID; } |
50 | bool operator!=(const FileID &RHS) const { return !(*this == RHS); } |
51 | bool operator>(const FileID &RHS) const { return RHS < *this; } |
52 | bool operator>=(const FileID &RHS) const { return RHS <= *this; } |
53 | |
54 | static FileID getSentinel() { return get(-1); } |
55 | unsigned getHashValue() const { return static_cast<unsigned>(ID); } |
56 | |
57 | private: |
58 | friend class ASTWriter; |
59 | friend class ASTReader; |
60 | friend class SourceManager; |
61 | |
62 | static FileID get(int V) { |
63 | FileID F; |
64 | F.ID = V; |
65 | return F; |
66 | } |
67 | |
68 | int getOpaqueValue() const { return ID; } |
69 | }; |
70 | |
71 | /// Encodes a location in the source. The SourceManager can decode this |
72 | /// to get at the full include stack, line and column information. |
73 | /// |
74 | /// Technically, a source location is simply an offset into the manager's view |
75 | /// of the input source, which is all input buffers (including macro |
76 | /// expansions) concatenated in an effectively arbitrary order. The manager |
77 | /// actually maintains two blocks of input buffers. One, starting at offset |
78 | /// 0 and growing upwards, contains all buffers from this module. The other, |
79 | /// starting at the highest possible offset and growing downwards, contains |
80 | /// buffers of loaded modules. |
81 | /// |
82 | /// In addition, one bit of SourceLocation is used for quick access to the |
83 | /// information whether the location is in a file or a macro expansion. |
84 | /// |
85 | /// It is important that this type remains small. It is currently 32 bits wide. |
86 | class SourceLocation { |
87 | friend class ASTReader; |
88 | friend class ASTWriter; |
89 | friend class SourceManager; |
90 | |
91 | unsigned ID = 0; |
92 | |
93 | enum : unsigned { |
94 | MacroIDBit = 1U << 31 |
95 | }; |
96 | |
97 | public: |
98 | bool isFileID() const { return (ID & MacroIDBit) == 0; } |
99 | bool isMacroID() const { return (ID & MacroIDBit) != 0; } |
100 | |
101 | /// Return true if this is a valid SourceLocation object. |
102 | /// |
103 | /// Invalid SourceLocations are often used when events have no corresponding |
104 | /// location in the source (e.g. a diagnostic is required for a command line |
105 | /// option). |
106 | bool isValid() const { return ID != 0; } |
107 | bool isInvalid() const { return ID == 0; } |
108 | |
109 | private: |
110 | /// Return the offset into the manager's global input view. |
111 | unsigned getOffset() const { |
112 | return ID & ~MacroIDBit; |
113 | } |
114 | |
115 | static SourceLocation getFileLoc(unsigned ID) { |
116 | assert((ID & MacroIDBit) == 0 && "Ran out of source locations!")(((ID & MacroIDBit) == 0 && "Ran out of source locations!" ) ? static_cast<void> (0) : __assert_fail ("(ID & MacroIDBit) == 0 && \"Ran out of source locations!\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/include/clang/Basic/SourceLocation.h" , 116, __PRETTY_FUNCTION__)); |
117 | SourceLocation L; |
118 | L.ID = ID; |
119 | return L; |
120 | } |
121 | |
122 | static SourceLocation getMacroLoc(unsigned ID) { |
123 | assert((ID & MacroIDBit) == 0 && "Ran out of source locations!")(((ID & MacroIDBit) == 0 && "Ran out of source locations!" ) ? static_cast<void> (0) : __assert_fail ("(ID & MacroIDBit) == 0 && \"Ran out of source locations!\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/include/clang/Basic/SourceLocation.h" , 123, __PRETTY_FUNCTION__)); |
124 | SourceLocation L; |
125 | L.ID = MacroIDBit | ID; |
126 | return L; |
127 | } |
128 | |
129 | public: |
130 | /// Return a source location with the specified offset from this |
131 | /// SourceLocation. |
132 | SourceLocation getLocWithOffset(int Offset) const { |
133 | assert(((getOffset()+Offset) & MacroIDBit) == 0 && "offset overflow")((((getOffset()+Offset) & MacroIDBit) == 0 && "offset overflow" ) ? static_cast<void> (0) : __assert_fail ("((getOffset()+Offset) & MacroIDBit) == 0 && \"offset overflow\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/include/clang/Basic/SourceLocation.h" , 133, __PRETTY_FUNCTION__)); |
134 | SourceLocation L; |
135 | L.ID = ID+Offset; |
136 | return L; |
137 | } |
138 | |
139 | /// When a SourceLocation itself cannot be used, this returns |
140 | /// an (opaque) 32-bit integer encoding for it. |
141 | /// |
142 | /// This should only be passed to SourceLocation::getFromRawEncoding, it |
143 | /// should not be inspected directly. |
144 | unsigned getRawEncoding() const { return ID; } |
145 | |
146 | /// Turn a raw encoding of a SourceLocation object into |
147 | /// a real SourceLocation. |
148 | /// |
149 | /// \see getRawEncoding. |
150 | static SourceLocation getFromRawEncoding(unsigned Encoding) { |
151 | SourceLocation X; |
152 | X.ID = Encoding; |
153 | return X; |
154 | } |
155 | |
156 | /// When a SourceLocation itself cannot be used, this returns |
157 | /// an (opaque) pointer encoding for it. |
158 | /// |
159 | /// This should only be passed to SourceLocation::getFromPtrEncoding, it |
160 | /// should not be inspected directly. |
161 | void* getPtrEncoding() const { |
162 | // Double cast to avoid a warning "cast to pointer from integer of different |
163 | // size". |
164 | return (void*)(uintptr_t)getRawEncoding(); |
165 | } |
166 | |
167 | /// Turn a pointer encoding of a SourceLocation object back |
168 | /// into a real SourceLocation. |
169 | static SourceLocation getFromPtrEncoding(const void *Encoding) { |
170 | return getFromRawEncoding((unsigned)(uintptr_t)Encoding); |
171 | } |
172 | |
173 | static bool isPairOfFileLocations(SourceLocation Start, SourceLocation End) { |
174 | return Start.isValid() && Start.isFileID() && End.isValid() && |
175 | End.isFileID(); |
176 | } |
177 | |
178 | void print(raw_ostream &OS, const SourceManager &SM) const; |
179 | std::string printToString(const SourceManager &SM) const; |
180 | void dump(const SourceManager &SM) const; |
181 | }; |
182 | |
183 | inline bool operator==(const SourceLocation &LHS, const SourceLocation &RHS) { |
184 | return LHS.getRawEncoding() == RHS.getRawEncoding(); |
185 | } |
186 | |
187 | inline bool operator!=(const SourceLocation &LHS, const SourceLocation &RHS) { |
188 | return !(LHS == RHS); |
189 | } |
190 | |
191 | // Ordering is meaningful only if LHS and RHS have the same FileID! |
192 | // Otherwise use SourceManager::isBeforeInTranslationUnit(). |
193 | inline bool operator<(const SourceLocation &LHS, const SourceLocation &RHS) { |
194 | return LHS.getRawEncoding() < RHS.getRawEncoding(); |
195 | } |
196 | inline bool operator>(const SourceLocation &LHS, const SourceLocation &RHS) { |
197 | return LHS.getRawEncoding() > RHS.getRawEncoding(); |
198 | } |
199 | inline bool operator<=(const SourceLocation &LHS, const SourceLocation &RHS) { |
200 | return LHS.getRawEncoding() <= RHS.getRawEncoding(); |
201 | } |
202 | inline bool operator>=(const SourceLocation &LHS, const SourceLocation &RHS) { |
203 | return LHS.getRawEncoding() >= RHS.getRawEncoding(); |
204 | } |
205 | |
206 | /// A trivial tuple used to represent a source range. |
207 | class SourceRange { |
208 | SourceLocation B; |
209 | SourceLocation E; |
210 | |
211 | public: |
212 | SourceRange() = default; |
213 | SourceRange(SourceLocation loc) : B(loc), E(loc) {} |
214 | SourceRange(SourceLocation begin, SourceLocation end) : B(begin), E(end) {} |
215 | |
216 | SourceLocation getBegin() const { return B; } |
217 | SourceLocation getEnd() const { return E; } |
218 | |
219 | void setBegin(SourceLocation b) { B = b; } |
220 | void setEnd(SourceLocation e) { E = e; } |
221 | |
222 | bool isValid() const { return B.isValid() && E.isValid(); } |
223 | bool isInvalid() const { return !isValid(); } |
224 | |
225 | bool operator==(const SourceRange &X) const { |
226 | return B == X.B && E == X.E; |
227 | } |
228 | |
229 | bool operator!=(const SourceRange &X) const { |
230 | return B != X.B || E != X.E; |
231 | } |
232 | |
233 | // Returns true iff other is wholly contained within this range. |
234 | bool fullyContains(const SourceRange &other) const { |
235 | return B <= other.B && E >= other.E; |
236 | } |
237 | |
238 | void print(raw_ostream &OS, const SourceManager &SM) const; |
239 | std::string printToString(const SourceManager &SM) const; |
240 | void dump(const SourceManager &SM) const; |
241 | }; |
242 | |
243 | /// Represents a character-granular source range. |
244 | /// |
245 | /// The underlying SourceRange can either specify the starting/ending character |
246 | /// of the range, or it can specify the start of the range and the start of the |
247 | /// last token of the range (a "token range"). In the token range case, the |
248 | /// size of the last token must be measured to determine the actual end of the |
249 | /// range. |
250 | class CharSourceRange { |
251 | SourceRange Range; |
252 | bool IsTokenRange = false; |
253 | |
254 | public: |
255 | CharSourceRange() = default; |
256 | CharSourceRange(SourceRange R, bool ITR) : Range(R), IsTokenRange(ITR) {} |
257 | |
258 | static CharSourceRange getTokenRange(SourceRange R) { |
259 | return CharSourceRange(R, true); |
260 | } |
261 | |
262 | static CharSourceRange getCharRange(SourceRange R) { |
263 | return CharSourceRange(R, false); |
264 | } |
265 | |
266 | static CharSourceRange getTokenRange(SourceLocation B, SourceLocation E) { |
267 | return getTokenRange(SourceRange(B, E)); |
268 | } |
269 | |
270 | static CharSourceRange getCharRange(SourceLocation B, SourceLocation E) { |
271 | return getCharRange(SourceRange(B, E)); |
272 | } |
273 | |
274 | /// Return true if the end of this range specifies the start of |
275 | /// the last token. Return false if the end of this range specifies the last |
276 | /// character in the range. |
277 | bool isTokenRange() const { return IsTokenRange; } |
278 | bool isCharRange() const { return !IsTokenRange; } |
279 | |
280 | SourceLocation getBegin() const { return Range.getBegin(); } |
281 | SourceLocation getEnd() const { return Range.getEnd(); } |
282 | SourceRange getAsRange() const { return Range; } |
283 | |
284 | void setBegin(SourceLocation b) { Range.setBegin(b); } |
285 | void setEnd(SourceLocation e) { Range.setEnd(e); } |
286 | void setTokenRange(bool TR) { IsTokenRange = TR; } |
287 | |
288 | bool isValid() const { return Range.isValid(); } |
289 | bool isInvalid() const { return !isValid(); } |
290 | }; |
291 | |
292 | /// Represents an unpacked "presumed" location which can be presented |
293 | /// to the user. |
294 | /// |
295 | /// A 'presumed' location can be modified by \#line and GNU line marker |
296 | /// directives and is always the expansion point of a normal location. |
297 | /// |
298 | /// You can get a PresumedLoc from a SourceLocation with SourceManager. |
299 | class PresumedLoc { |
300 | const char *Filename = nullptr; |
301 | FileID ID; |
302 | unsigned Line, Col; |
303 | SourceLocation IncludeLoc; |
304 | |
305 | public: |
306 | PresumedLoc() = default; |
307 | PresumedLoc(const char *FN, FileID FID, unsigned Ln, unsigned Co, |
308 | SourceLocation IL) |
309 | : Filename(FN), ID(FID), Line(Ln), Col(Co), IncludeLoc(IL) {} |
310 | |
311 | /// Return true if this object is invalid or uninitialized. |
312 | /// |
313 | /// This occurs when created with invalid source locations or when walking |
314 | /// off the top of a \#include stack. |
315 | bool isInvalid() const { return Filename == nullptr; } |
316 | bool isValid() const { return Filename != nullptr; } |
317 | |
318 | /// Return the presumed filename of this location. |
319 | /// |
320 | /// This can be affected by \#line etc. |
321 | const char *getFilename() const { |
322 | assert(isValid())((isValid()) ? static_cast<void> (0) : __assert_fail ("isValid()" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/include/clang/Basic/SourceLocation.h" , 322, __PRETTY_FUNCTION__)); |
323 | return Filename; |
324 | } |
325 | |
326 | FileID getFileID() const { |
327 | assert(isValid())((isValid()) ? static_cast<void> (0) : __assert_fail ("isValid()" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/include/clang/Basic/SourceLocation.h" , 327, __PRETTY_FUNCTION__)); |
328 | return ID; |
329 | } |
330 | |
331 | /// Return the presumed line number of this location. |
332 | /// |
333 | /// This can be affected by \#line etc. |
334 | unsigned getLine() const { |
335 | assert(isValid())((isValid()) ? static_cast<void> (0) : __assert_fail ("isValid()" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/include/clang/Basic/SourceLocation.h" , 335, __PRETTY_FUNCTION__)); |
336 | return Line; |
337 | } |
338 | |
339 | /// Return the presumed column number of this location. |
340 | /// |
341 | /// This cannot be affected by \#line, but is packaged here for convenience. |
342 | unsigned getColumn() const { |
343 | assert(isValid())((isValid()) ? static_cast<void> (0) : __assert_fail ("isValid()" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/include/clang/Basic/SourceLocation.h" , 343, __PRETTY_FUNCTION__)); |
344 | return Col; |
345 | } |
346 | |
347 | /// Return the presumed include location of this location. |
348 | /// |
349 | /// This can be affected by GNU linemarker directives. |
350 | SourceLocation getIncludeLoc() const { |
351 | assert(isValid())((isValid()) ? static_cast<void> (0) : __assert_fail ("isValid()" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/include/clang/Basic/SourceLocation.h" , 351, __PRETTY_FUNCTION__)); |
352 | return IncludeLoc; |
353 | } |
354 | }; |
355 | |
356 | class FileEntry; |
357 | |
358 | /// A SourceLocation and its associated SourceManager. |
359 | /// |
360 | /// This is useful for argument passing to functions that expect both objects. |
361 | class FullSourceLoc : public SourceLocation { |
362 | const SourceManager *SrcMgr = nullptr; |
363 | |
364 | public: |
365 | /// Creates a FullSourceLoc where isValid() returns \c false. |
366 | FullSourceLoc() = default; |
367 | |
368 | explicit FullSourceLoc(SourceLocation Loc, const SourceManager &SM) |
369 | : SourceLocation(Loc), SrcMgr(&SM) {} |
370 | |
371 | bool hasManager() const { |
372 | bool hasSrcMgr = SrcMgr != nullptr; |
373 | assert(hasSrcMgr == isValid() && "FullSourceLoc has location but no manager")((hasSrcMgr == isValid() && "FullSourceLoc has location but no manager" ) ? static_cast<void> (0) : __assert_fail ("hasSrcMgr == isValid() && \"FullSourceLoc has location but no manager\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/include/clang/Basic/SourceLocation.h" , 373, __PRETTY_FUNCTION__)); |
374 | return hasSrcMgr; |
375 | } |
376 | |
377 | /// \pre This FullSourceLoc has an associated SourceManager. |
378 | const SourceManager &getManager() const { |
379 | assert(SrcMgr && "SourceManager is NULL.")((SrcMgr && "SourceManager is NULL.") ? static_cast< void> (0) : __assert_fail ("SrcMgr && \"SourceManager is NULL.\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/include/clang/Basic/SourceLocation.h" , 379, __PRETTY_FUNCTION__)); |
380 | return *SrcMgr; |
381 | } |
382 | |
383 | FileID getFileID() const; |
384 | |
385 | FullSourceLoc getExpansionLoc() const; |
386 | FullSourceLoc getSpellingLoc() const; |
387 | FullSourceLoc getFileLoc() const; |
388 | PresumedLoc getPresumedLoc(bool UseLineDirectives = true) const; |
389 | bool isMacroArgExpansion(FullSourceLoc *StartLoc = nullptr) const; |
390 | FullSourceLoc getImmediateMacroCallerLoc() const; |
391 | std::pair<FullSourceLoc, StringRef> getModuleImportLoc() const; |
392 | unsigned getFileOffset() const; |
393 | |
394 | unsigned getExpansionLineNumber(bool *Invalid = nullptr) const; |
395 | unsigned getExpansionColumnNumber(bool *Invalid = nullptr) const; |
396 | |
397 | unsigned getSpellingLineNumber(bool *Invalid = nullptr) const; |
398 | unsigned getSpellingColumnNumber(bool *Invalid = nullptr) const; |
399 | |
400 | const char *getCharacterData(bool *Invalid = nullptr) const; |
401 | |
402 | unsigned getLineNumber(bool *Invalid = nullptr) const; |
403 | unsigned getColumnNumber(bool *Invalid = nullptr) const; |
404 | |
405 | const FileEntry *getFileEntry() const; |
406 | |
407 | /// Return a StringRef to the source buffer data for the |
408 | /// specified FileID. |
409 | StringRef getBufferData(bool *Invalid = nullptr) const; |
410 | |
411 | /// Decompose the specified location into a raw FileID + Offset pair. |
412 | /// |
413 | /// The first element is the FileID, the second is the offset from the |
414 | /// start of the buffer of the location. |
415 | std::pair<FileID, unsigned> getDecomposedLoc() const; |
416 | |
417 | bool isInSystemHeader() const; |
418 | |
419 | /// Determines the order of 2 source locations in the translation unit. |
420 | /// |
421 | /// \returns true if this source location comes before 'Loc', false otherwise. |
422 | bool isBeforeInTranslationUnitThan(SourceLocation Loc) const; |
423 | |
424 | /// Determines the order of 2 source locations in the translation unit. |
425 | /// |
426 | /// \returns true if this source location comes before 'Loc', false otherwise. |
427 | bool isBeforeInTranslationUnitThan(FullSourceLoc Loc) const { |
428 | assert(Loc.isValid())((Loc.isValid()) ? static_cast<void> (0) : __assert_fail ("Loc.isValid()", "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/include/clang/Basic/SourceLocation.h" , 428, __PRETTY_FUNCTION__)); |
429 | assert(SrcMgr == Loc.SrcMgr && "Loc comes from another SourceManager!")((SrcMgr == Loc.SrcMgr && "Loc comes from another SourceManager!" ) ? static_cast<void> (0) : __assert_fail ("SrcMgr == Loc.SrcMgr && \"Loc comes from another SourceManager!\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/clang/include/clang/Basic/SourceLocation.h" , 429, __PRETTY_FUNCTION__)); |
430 | return isBeforeInTranslationUnitThan((SourceLocation)Loc); |
431 | } |
432 | |
433 | /// Comparison function class, useful for sorting FullSourceLocs. |
434 | struct BeforeThanCompare { |
435 | bool operator()(const FullSourceLoc& lhs, const FullSourceLoc& rhs) const { |
436 | return lhs.isBeforeInTranslationUnitThan(rhs); |
437 | } |
438 | }; |
439 | |
440 | /// Prints information about this FullSourceLoc to stderr. |
441 | /// |
442 | /// This is useful for debugging. |
443 | void dump() const; |
444 | |
445 | friend bool |
446 | operator==(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { |
447 | return LHS.getRawEncoding() == RHS.getRawEncoding() && |
448 | LHS.SrcMgr == RHS.SrcMgr; |
449 | } |
450 | |
451 | friend bool |
452 | operator!=(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { |
453 | return !(LHS == RHS); |
454 | } |
455 | }; |
456 | |
457 | } // namespace clang |
458 | |
459 | namespace llvm { |
460 | |
461 | /// Define DenseMapInfo so that FileID's can be used as keys in DenseMap and |
462 | /// DenseSets. |
463 | template <> |
464 | struct DenseMapInfo<clang::FileID> { |
465 | static clang::FileID getEmptyKey() { |
466 | return {}; |
467 | } |
468 | |
469 | static clang::FileID getTombstoneKey() { |
470 | return clang::FileID::getSentinel(); |
471 | } |
472 | |
473 | static unsigned getHashValue(clang::FileID S) { |
474 | return S.getHashValue(); |
475 | } |
476 | |
477 | static bool isEqual(clang::FileID LHS, clang::FileID RHS) { |
478 | return LHS == RHS; |
479 | } |
480 | }; |
481 | |
482 | // Teach SmallPtrSet how to handle SourceLocation. |
483 | template<> |
484 | struct PointerLikeTypeTraits<clang::SourceLocation> { |
485 | static constexpr int NumLowBitsAvailable = 0; |
486 | |
487 | static void *getAsVoidPointer(clang::SourceLocation L) { |
488 | return L.getPtrEncoding(); |
489 | } |
490 | |
491 | static clang::SourceLocation getFromVoidPointer(void *P) { |
492 | return clang::SourceLocation::getFromRawEncoding((unsigned)(uintptr_t)P); |
493 | } |
494 | }; |
495 | |
496 | } // namespace llvm |
497 | |
498 | #endif // LLVM_CLANG_BASIC_SOURCELOCATION_H |