blob: d08e84dacd21dc22e5c88ce5c115b85ab3972f00 [file] [log] [blame]
Sebastian Redldced2262009-10-11 09:03:14 +00001//===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file provides Sema routines for C++ exception specification testing.
11//
12//===----------------------------------------------------------------------===//
13
John McCall2d887082010-08-25 22:03:47 +000014#include "clang/Sema/SemaInternal.h"
Sebastian Redldced2262009-10-11 09:03:14 +000015#include "clang/AST/CXXInheritance.h"
16#include "clang/AST/Expr.h"
17#include "clang/AST/ExprCXX.h"
Douglas Gregor2eef8292010-03-24 07:14:45 +000018#include "clang/AST/TypeLoc.h"
19#include "clang/Lex/Preprocessor.h"
Douglas Gregore13ad832010-02-12 07:32:17 +000020#include "clang/Basic/Diagnostic.h"
21#include "clang/Basic/SourceManager.h"
Sebastian Redldced2262009-10-11 09:03:14 +000022#include "llvm/ADT/SmallPtrSet.h"
23
24namespace clang {
25
26static const FunctionProtoType *GetUnderlyingFunction(QualType T)
27{
28 if (const PointerType *PtrTy = T->getAs<PointerType>())
29 T = PtrTy->getPointeeType();
30 else if (const ReferenceType *RefTy = T->getAs<ReferenceType>())
31 T = RefTy->getPointeeType();
Sebastian Redlc3a3b7b2009-10-14 14:38:54 +000032 else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>())
33 T = MPTy->getPointeeType();
Sebastian Redldced2262009-10-11 09:03:14 +000034 return T->getAs<FunctionProtoType>();
35}
36
37/// CheckSpecifiedExceptionType - Check if the given type is valid in an
38/// exception specification. Incomplete types, or pointers to incomplete types
39/// other than void are not allowed.
40bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
Sebastian Redldced2262009-10-11 09:03:14 +000041
Douglas Gregor0966f352009-12-10 18:13:52 +000042 // This check (and the similar one below) deals with issue 437, that changes
43 // C++ 9.2p2 this way:
44 // Within the class member-specification, the class is regarded as complete
45 // within function bodies, default arguments, exception-specifications, and
46 // constructor ctor-initializers (including such things in nested classes).
47 if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined())
48 return false;
49
Sebastian Redldced2262009-10-11 09:03:14 +000050 // C++ 15.4p2: A type denoted in an exception-specification shall not denote
51 // an incomplete type.
Sebastian Redl491b84c2009-10-14 14:59:48 +000052 if (RequireCompleteType(Range.getBegin(), T,
53 PDiag(diag::err_incomplete_in_exception_spec) << /*direct*/0 << Range))
54 return true;
Sebastian Redldced2262009-10-11 09:03:14 +000055
56 // C++ 15.4p2: A type denoted in an exception-specification shall not denote
57 // an incomplete type a pointer or reference to an incomplete type, other
58 // than (cv) void*.
59 int kind;
60 if (const PointerType* IT = T->getAs<PointerType>()) {
61 T = IT->getPointeeType();
62 kind = 1;
63 } else if (const ReferenceType* IT = T->getAs<ReferenceType>()) {
64 T = IT->getPointeeType();
65 kind = 2;
66 } else
67 return false;
68
Douglas Gregor0966f352009-12-10 18:13:52 +000069 // Again as before
70 if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined())
71 return false;
72
Sebastian Redl491b84c2009-10-14 14:59:48 +000073 if (!T->isVoidType() && RequireCompleteType(Range.getBegin(), T,
Douglas Gregor0966f352009-12-10 18:13:52 +000074 PDiag(diag::err_incomplete_in_exception_spec) << kind << Range))
Sebastian Redl491b84c2009-10-14 14:59:48 +000075 return true;
Sebastian Redldced2262009-10-11 09:03:14 +000076
77 return false;
78}
79
80/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
81/// to member to a function with an exception specification. This means that
82/// it is invalid to add another level of indirection.
83bool Sema::CheckDistantExceptionSpec(QualType T) {
Abramo Bagnara075f8f12010-12-10 16:29:40 +000084 T = T.IgnoreParens();
Sebastian Redldced2262009-10-11 09:03:14 +000085 if (const PointerType *PT = T->getAs<PointerType>())
86 T = PT->getPointeeType();
87 else if (const MemberPointerType *PT = T->getAs<MemberPointerType>())
88 T = PT->getPointeeType();
89 else
90 return false;
91
Abramo Bagnara075f8f12010-12-10 16:29:40 +000092 T = T.IgnoreParens();
Sebastian Redldced2262009-10-11 09:03:14 +000093 const FunctionProtoType *FnT = T->getAs<FunctionProtoType>();
94 if (!FnT)
95 return false;
96
97 return FnT->hasExceptionSpec();
98}
99
Douglas Gregore13ad832010-02-12 07:32:17 +0000100bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
Douglas Gregor2eef8292010-03-24 07:14:45 +0000101 bool MissingExceptionSpecification = false;
Douglas Gregore13ad832010-02-12 07:32:17 +0000102 bool MissingEmptyExceptionSpecification = false;
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000103 if (!CheckEquivalentExceptionSpec(PDiag(diag::err_mismatched_exception_spec),
104 PDiag(diag::note_previous_declaration),
Douglas Gregore13ad832010-02-12 07:32:17 +0000105 Old->getType()->getAs<FunctionProtoType>(),
106 Old->getLocation(),
107 New->getType()->getAs<FunctionProtoType>(),
108 New->getLocation(),
Douglas Gregor2eef8292010-03-24 07:14:45 +0000109 &MissingExceptionSpecification,
Douglas Gregore13ad832010-02-12 07:32:17 +0000110 &MissingEmptyExceptionSpecification))
111 return false;
112
113 // The failure was something other than an empty exception
114 // specification; return an error.
Douglas Gregor2eef8292010-03-24 07:14:45 +0000115 if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification)
Douglas Gregore13ad832010-02-12 07:32:17 +0000116 return true;
117
John McCall0e88aa72010-12-14 06:51:39 +0000118 const FunctionProtoType *NewProto
119 = New->getType()->getAs<FunctionProtoType>();
120
Douglas Gregore13ad832010-02-12 07:32:17 +0000121 // The new function declaration is only missing an empty exception
122 // specification "throw()". If the throw() specification came from a
123 // function in a system header that has C linkage, just add an empty
124 // exception specification to the "new" declaration. This is an
125 // egregious workaround for glibc, which adds throw() specifications
126 // to many libc functions as an optimization. Unfortunately, that
127 // optimization isn't permitted by the C++ standard, so we're forced
128 // to work around it here.
John McCall0e88aa72010-12-14 06:51:39 +0000129 if (MissingEmptyExceptionSpecification && NewProto &&
Douglas Gregor2eef8292010-03-24 07:14:45 +0000130 (Old->getLocation().isInvalid() ||
131 Context.getSourceManager().isInSystemHeader(Old->getLocation())) &&
Douglas Gregore13ad832010-02-12 07:32:17 +0000132 Old->isExternC()) {
John McCall0e88aa72010-12-14 06:51:39 +0000133 FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
134 EPI.HasExceptionSpec = true;
135 EPI.HasAnyExceptionSpec = false;
136 EPI.NumExceptions = 0;
Douglas Gregore13ad832010-02-12 07:32:17 +0000137 QualType NewType = Context.getFunctionType(NewProto->getResultType(),
138 NewProto->arg_type_begin(),
139 NewProto->getNumArgs(),
John McCall0e88aa72010-12-14 06:51:39 +0000140 EPI);
Douglas Gregore13ad832010-02-12 07:32:17 +0000141 New->setType(NewType);
142 return false;
143 }
144
John McCall0e88aa72010-12-14 06:51:39 +0000145 if (MissingExceptionSpecification && NewProto) {
Douglas Gregor2eef8292010-03-24 07:14:45 +0000146 const FunctionProtoType *OldProto
147 = Old->getType()->getAs<FunctionProtoType>();
148
John McCall0e88aa72010-12-14 06:51:39 +0000149 FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
150 EPI.HasExceptionSpec = OldProto->hasExceptionSpec();
151 EPI.HasAnyExceptionSpec = OldProto->hasAnyExceptionSpec();
152 EPI.NumExceptions = OldProto->getNumExceptions();
153 EPI.Exceptions = OldProto->exception_begin();
154
Douglas Gregor2eef8292010-03-24 07:14:45 +0000155 // Update the type of the function with the appropriate exception
156 // specification.
157 QualType NewType = Context.getFunctionType(NewProto->getResultType(),
158 NewProto->arg_type_begin(),
159 NewProto->getNumArgs(),
John McCall0e88aa72010-12-14 06:51:39 +0000160 EPI);
Douglas Gregor2eef8292010-03-24 07:14:45 +0000161 New->setType(NewType);
162
163 // If exceptions are disabled, suppress the warning about missing
164 // exception specifications for new and delete operators.
165 if (!getLangOptions().Exceptions) {
166 switch (New->getDeclName().getCXXOverloadedOperator()) {
167 case OO_New:
168 case OO_Array_New:
169 case OO_Delete:
170 case OO_Array_Delete:
171 if (New->getDeclContext()->isTranslationUnit())
172 return false;
173 break;
174
175 default:
176 break;
177 }
178 }
179
180 // Warn about the lack of exception specification.
181 llvm::SmallString<128> ExceptionSpecString;
182 llvm::raw_svector_ostream OS(ExceptionSpecString);
183 OS << "throw(";
184 bool OnFirstException = true;
185 for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(),
186 EEnd = OldProto->exception_end();
187 E != EEnd;
188 ++E) {
189 if (OnFirstException)
190 OnFirstException = false;
191 else
192 OS << ", ";
193
194 OS << E->getAsString(Context.PrintingPolicy);
195 }
196 OS << ")";
197 OS.flush();
198
199 SourceLocation AfterParenLoc;
200 if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) {
201 TypeLoc TL = TSInfo->getTypeLoc();
202 if (const FunctionTypeLoc *FTLoc = dyn_cast<FunctionTypeLoc>(&TL))
203 AfterParenLoc = PP.getLocForEndOfToken(FTLoc->getRParenLoc());
204 }
205
206 if (AfterParenLoc.isInvalid())
207 Diag(New->getLocation(), diag::warn_missing_exception_specification)
208 << New << OS.str();
209 else {
210 // FIXME: This will get more complicated with C++0x
211 // late-specified return types.
212 Diag(New->getLocation(), diag::warn_missing_exception_specification)
213 << New << OS.str()
Douglas Gregor849b2432010-03-31 17:46:05 +0000214 << FixItHint::CreateInsertion(AfterParenLoc, " " + OS.str().str());
Douglas Gregor2eef8292010-03-24 07:14:45 +0000215 }
216
217 if (!Old->getLocation().isInvalid())
218 Diag(Old->getLocation(), diag::note_previous_declaration);
219
220 return false;
221 }
222
Douglas Gregore13ad832010-02-12 07:32:17 +0000223 Diag(New->getLocation(), diag::err_mismatched_exception_spec);
224 Diag(Old->getLocation(), diag::note_previous_declaration);
225 return true;
226}
227
Sebastian Redldced2262009-10-11 09:03:14 +0000228/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
229/// exception specifications. Exception specifications are equivalent if
230/// they allow exactly the same set of exception types. It does not matter how
231/// that is achieved. See C++ [except.spec]p2.
232bool Sema::CheckEquivalentExceptionSpec(
233 const FunctionProtoType *Old, SourceLocation OldLoc,
234 const FunctionProtoType *New, SourceLocation NewLoc) {
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000235 return CheckEquivalentExceptionSpec(
236 PDiag(diag::err_mismatched_exception_spec),
237 PDiag(diag::note_previous_declaration),
Sebastian Redldced2262009-10-11 09:03:14 +0000238 Old, OldLoc, New, NewLoc);
239}
240
241/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
242/// exception specifications. Exception specifications are equivalent if
243/// they allow exactly the same set of exception types. It does not matter how
244/// that is achieved. See C++ [except.spec]p2.
Douglas Gregor2eef8292010-03-24 07:14:45 +0000245bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
246 const PartialDiagnostic & NoteID,
247 const FunctionProtoType *Old,
248 SourceLocation OldLoc,
249 const FunctionProtoType *New,
250 SourceLocation NewLoc,
251 bool *MissingExceptionSpecification,
252 bool *MissingEmptyExceptionSpecification) {
John McCall811d0be2010-05-28 08:37:35 +0000253 // Just completely ignore this under -fno-exceptions.
254 if (!getLangOptions().Exceptions)
255 return false;
256
Douglas Gregor2eef8292010-03-24 07:14:45 +0000257 if (MissingExceptionSpecification)
258 *MissingExceptionSpecification = false;
259
Douglas Gregore13ad832010-02-12 07:32:17 +0000260 if (MissingEmptyExceptionSpecification)
261 *MissingEmptyExceptionSpecification = false;
262
Sebastian Redldced2262009-10-11 09:03:14 +0000263 bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec();
264 bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec();
Douglas Gregor5b6f7692010-08-30 15:04:51 +0000265 if (getLangOptions().Microsoft) {
266 // Treat throw(whatever) as throw(...) to be compatible with MS headers.
267 if (New->hasExceptionSpec() && New->getNumExceptions() > 0)
268 NewAny = true;
269 if (Old->hasExceptionSpec() && Old->getNumExceptions() > 0)
270 OldAny = true;
271 }
272
Sebastian Redldced2262009-10-11 09:03:14 +0000273 if (OldAny && NewAny)
274 return false;
275 if (OldAny || NewAny) {
Douglas Gregor2eef8292010-03-24 07:14:45 +0000276 if (MissingExceptionSpecification && Old->hasExceptionSpec() &&
Douglas Gregore13ad832010-02-12 07:32:17 +0000277 !New->hasExceptionSpec()) {
Douglas Gregor2eef8292010-03-24 07:14:45 +0000278 // The old type has an exception specification of some sort, but
279 // the new type does not.
280 *MissingExceptionSpecification = true;
281
282 if (MissingEmptyExceptionSpecification &&
283 !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0) {
284 // The old type has a throw() exception specification and the
285 // new type has no exception specification, and the caller asked
286 // to handle this itself.
287 *MissingEmptyExceptionSpecification = true;
288 }
289
Douglas Gregore13ad832010-02-12 07:32:17 +0000290 return true;
291 }
292
Sebastian Redldced2262009-10-11 09:03:14 +0000293 Diag(NewLoc, DiagID);
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000294 if (NoteID.getDiagID() != 0)
Sebastian Redldced2262009-10-11 09:03:14 +0000295 Diag(OldLoc, NoteID);
296 return true;
297 }
298
299 bool Success = true;
300 // Both have a definite exception spec. Collect the first set, then compare
301 // to the second.
Sebastian Redl1219d152009-10-14 15:06:25 +0000302 llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes;
Sebastian Redldced2262009-10-11 09:03:14 +0000303 for (FunctionProtoType::exception_iterator I = Old->exception_begin(),
304 E = Old->exception_end(); I != E; ++I)
Sebastian Redl1219d152009-10-14 15:06:25 +0000305 OldTypes.insert(Context.getCanonicalType(*I).getUnqualifiedType());
Sebastian Redldced2262009-10-11 09:03:14 +0000306
307 for (FunctionProtoType::exception_iterator I = New->exception_begin(),
Sebastian Redl5db4d902009-10-11 09:11:23 +0000308 E = New->exception_end(); I != E && Success; ++I) {
Sebastian Redl1219d152009-10-14 15:06:25 +0000309 CanQualType TypePtr = Context.getCanonicalType(*I).getUnqualifiedType();
Sebastian Redl5db4d902009-10-11 09:11:23 +0000310 if(OldTypes.count(TypePtr))
311 NewTypes.insert(TypePtr);
312 else
313 Success = false;
314 }
Sebastian Redldced2262009-10-11 09:03:14 +0000315
Sebastian Redl5db4d902009-10-11 09:11:23 +0000316 Success = Success && OldTypes.size() == NewTypes.size();
Sebastian Redldced2262009-10-11 09:03:14 +0000317
318 if (Success) {
319 return false;
320 }
321 Diag(NewLoc, DiagID);
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000322 if (NoteID.getDiagID() != 0)
Sebastian Redldced2262009-10-11 09:03:14 +0000323 Diag(OldLoc, NoteID);
324 return true;
325}
326
327/// CheckExceptionSpecSubset - Check whether the second function type's
328/// exception specification is a subset (or equivalent) of the first function
329/// type. This is used by override and pointer assignment checks.
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000330bool Sema::CheckExceptionSpecSubset(
331 const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
Sebastian Redldced2262009-10-11 09:03:14 +0000332 const FunctionProtoType *Superset, SourceLocation SuperLoc,
333 const FunctionProtoType *Subset, SourceLocation SubLoc) {
John McCall811d0be2010-05-28 08:37:35 +0000334
335 // Just auto-succeed under -fno-exceptions.
336 if (!getLangOptions().Exceptions)
337 return false;
338
Sebastian Redldced2262009-10-11 09:03:14 +0000339 // FIXME: As usual, we could be more specific in our error messages, but
340 // that better waits until we've got types with source locations.
341
342 if (!SubLoc.isValid())
343 SubLoc = SuperLoc;
344
345 // If superset contains everything, we're done.
346 if (!Superset->hasExceptionSpec() || Superset->hasAnyExceptionSpec())
347 return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
348
349 // It does not. If the subset contains everything, we've failed.
350 if (!Subset->hasExceptionSpec() || Subset->hasAnyExceptionSpec()) {
351 Diag(SubLoc, DiagID);
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000352 if (NoteID.getDiagID() != 0)
Sebastian Redldced2262009-10-11 09:03:14 +0000353 Diag(SuperLoc, NoteID);
354 return true;
355 }
356
357 // Neither contains everything. Do a proper comparison.
358 for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(),
359 SubE = Subset->exception_end(); SubI != SubE; ++SubI) {
360 // Take one type from the subset.
361 QualType CanonicalSubT = Context.getCanonicalType(*SubI);
Sebastian Redlc3a3b7b2009-10-14 14:38:54 +0000362 // Unwrap pointers and references so that we can do checks within a class
363 // hierarchy. Don't unwrap member pointers; they don't have hierarchy
364 // conversions on the pointee.
Sebastian Redldced2262009-10-11 09:03:14 +0000365 bool SubIsPointer = false;
366 if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>())
367 CanonicalSubT = RefTy->getPointeeType();
368 if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) {
369 CanonicalSubT = PtrTy->getPointeeType();
370 SubIsPointer = true;
371 }
372 bool SubIsClass = CanonicalSubT->isRecordType();
Douglas Gregora4923eb2009-11-16 21:35:15 +0000373 CanonicalSubT = CanonicalSubT.getLocalUnqualifiedType();
Sebastian Redldced2262009-10-11 09:03:14 +0000374
375 CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
376 /*DetectVirtual=*/false);
377
378 bool Contained = false;
379 // Make sure it's in the superset.
380 for (FunctionProtoType::exception_iterator SuperI =
381 Superset->exception_begin(), SuperE = Superset->exception_end();
382 SuperI != SuperE; ++SuperI) {
383 QualType CanonicalSuperT = Context.getCanonicalType(*SuperI);
384 // SubT must be SuperT or derived from it, or pointer or reference to
385 // such types.
386 if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>())
387 CanonicalSuperT = RefTy->getPointeeType();
388 if (SubIsPointer) {
389 if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>())
390 CanonicalSuperT = PtrTy->getPointeeType();
391 else {
392 continue;
393 }
394 }
Douglas Gregora4923eb2009-11-16 21:35:15 +0000395 CanonicalSuperT = CanonicalSuperT.getLocalUnqualifiedType();
Sebastian Redldced2262009-10-11 09:03:14 +0000396 // If the types are the same, move on to the next type in the subset.
397 if (CanonicalSubT == CanonicalSuperT) {
398 Contained = true;
399 break;
400 }
401
402 // Otherwise we need to check the inheritance.
403 if (!SubIsClass || !CanonicalSuperT->isRecordType())
404 continue;
405
406 Paths.clear();
407 if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths))
408 continue;
409
Douglas Gregore0d5fe22010-05-21 20:29:55 +0000410 if (Paths.isAmbiguous(Context.getCanonicalType(CanonicalSuperT)))
Sebastian Redldced2262009-10-11 09:03:14 +0000411 continue;
412
John McCall6b2accb2010-02-10 09:31:12 +0000413 // Do this check from a context without privileges.
John McCall58e6f342010-03-16 05:22:47 +0000414 switch (CheckBaseClassAccess(SourceLocation(),
John McCall6b2accb2010-02-10 09:31:12 +0000415 CanonicalSuperT, CanonicalSubT,
416 Paths.front(),
John McCall58e6f342010-03-16 05:22:47 +0000417 /*Diagnostic*/ 0,
John McCall6b2accb2010-02-10 09:31:12 +0000418 /*ForceCheck*/ true,
John McCall58e6f342010-03-16 05:22:47 +0000419 /*ForceUnprivileged*/ true)) {
John McCall6b2accb2010-02-10 09:31:12 +0000420 case AR_accessible: break;
421 case AR_inaccessible: continue;
422 case AR_dependent:
423 llvm_unreachable("access check dependent for unprivileged context");
424 break;
425 case AR_delayed:
426 llvm_unreachable("access check delayed in non-declaration");
427 break;
428 }
Sebastian Redldced2262009-10-11 09:03:14 +0000429
430 Contained = true;
431 break;
432 }
433 if (!Contained) {
434 Diag(SubLoc, DiagID);
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000435 if (NoteID.getDiagID() != 0)
Sebastian Redldced2262009-10-11 09:03:14 +0000436 Diag(SuperLoc, NoteID);
437 return true;
438 }
439 }
440 // We've run half the gauntlet.
441 return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
442}
443
444static bool CheckSpecForTypesEquivalent(Sema &S,
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000445 const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
Sebastian Redldced2262009-10-11 09:03:14 +0000446 QualType Target, SourceLocation TargetLoc,
447 QualType Source, SourceLocation SourceLoc)
448{
449 const FunctionProtoType *TFunc = GetUnderlyingFunction(Target);
450 if (!TFunc)
451 return false;
452 const FunctionProtoType *SFunc = GetUnderlyingFunction(Source);
453 if (!SFunc)
454 return false;
455
456 return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc,
457 SFunc, SourceLoc);
458}
459
460/// CheckParamExceptionSpec - Check if the parameter and return types of the
461/// two functions have equivalent exception specs. This is part of the
462/// assignment and override compatibility check. We do not check the parameters
463/// of parameter function pointers recursively, as no sane programmer would
464/// even be able to write such a function type.
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000465bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
Sebastian Redldced2262009-10-11 09:03:14 +0000466 const FunctionProtoType *Target, SourceLocation TargetLoc,
467 const FunctionProtoType *Source, SourceLocation SourceLoc)
468{
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000469 if (CheckSpecForTypesEquivalent(*this,
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000470 PDiag(diag::err_deep_exception_specs_differ) << 0,
471 PDiag(),
Sebastian Redldced2262009-10-11 09:03:14 +0000472 Target->getResultType(), TargetLoc,
473 Source->getResultType(), SourceLoc))
474 return true;
475
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000476 // We shouldn't even be testing this unless the arguments are otherwise
Sebastian Redldced2262009-10-11 09:03:14 +0000477 // compatible.
478 assert(Target->getNumArgs() == Source->getNumArgs() &&
479 "Functions have different argument counts.");
480 for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) {
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000481 if (CheckSpecForTypesEquivalent(*this,
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000482 PDiag(diag::err_deep_exception_specs_differ) << 1,
483 PDiag(),
Sebastian Redldced2262009-10-11 09:03:14 +0000484 Target->getArgType(i), TargetLoc,
485 Source->getArgType(i), SourceLoc))
486 return true;
487 }
488 return false;
489}
490
491bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
492{
493 // First we check for applicability.
494 // Target type must be a function, function pointer or function reference.
495 const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType);
496 if (!ToFunc)
497 return false;
498
499 // SourceType must be a function or function pointer.
500 const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType());
501 if (!FromFunc)
502 return false;
503
504 // Now we've got the correct types on both sides, check their compatibility.
505 // This means that the source of the conversion can only throw a subset of
506 // the exceptions of the target, and any exception specs on arguments or
507 // return types must be equivalent.
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000508 return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs),
509 PDiag(), ToFunc,
510 From->getSourceRange().getBegin(),
Sebastian Redldced2262009-10-11 09:03:14 +0000511 FromFunc, SourceLocation());
512}
513
514bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
515 const CXXMethodDecl *Old) {
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000516 return CheckExceptionSpecSubset(PDiag(diag::err_override_exception_spec),
517 PDiag(diag::note_overridden_virtual_function),
Sebastian Redldced2262009-10-11 09:03:14 +0000518 Old->getType()->getAs<FunctionProtoType>(),
519 Old->getLocation(),
520 New->getType()->getAs<FunctionProtoType>(),
521 New->getLocation());
522}
523
524} // end namespace clang