blob: d0718d020b2bc7b1c95cbf349dcd980d8ecdcc15 [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
14#include "Sema.h"
15#include "clang/Basic/Diagnostic.h"
16#include "clang/AST/CXXInheritance.h"
17#include "clang/AST/Expr.h"
18#include "clang/AST/ExprCXX.h"
19#include "llvm/ADT/SmallPtrSet.h"
20
21namespace clang {
22
23static const FunctionProtoType *GetUnderlyingFunction(QualType T)
24{
25 if (const PointerType *PtrTy = T->getAs<PointerType>())
26 T = PtrTy->getPointeeType();
27 else if (const ReferenceType *RefTy = T->getAs<ReferenceType>())
28 T = RefTy->getPointeeType();
Sebastian Redlc3a3b7b2009-10-14 14:38:54 +000029 else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>())
30 T = MPTy->getPointeeType();
Sebastian Redldced2262009-10-11 09:03:14 +000031 return T->getAs<FunctionProtoType>();
32}
33
34/// CheckSpecifiedExceptionType - Check if the given type is valid in an
35/// exception specification. Incomplete types, or pointers to incomplete types
36/// other than void are not allowed.
37bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
Sebastian Redldced2262009-10-11 09:03:14 +000038
Douglas Gregor0966f352009-12-10 18:13:52 +000039 // This check (and the similar one below) deals with issue 437, that changes
40 // C++ 9.2p2 this way:
41 // Within the class member-specification, the class is regarded as complete
42 // within function bodies, default arguments, exception-specifications, and
43 // constructor ctor-initializers (including such things in nested classes).
44 if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined())
45 return false;
46
Sebastian Redldced2262009-10-11 09:03:14 +000047 // C++ 15.4p2: A type denoted in an exception-specification shall not denote
48 // an incomplete type.
Sebastian Redl491b84c2009-10-14 14:59:48 +000049 if (RequireCompleteType(Range.getBegin(), T,
50 PDiag(diag::err_incomplete_in_exception_spec) << /*direct*/0 << Range))
51 return true;
Sebastian Redldced2262009-10-11 09:03:14 +000052
53 // C++ 15.4p2: A type denoted in an exception-specification shall not denote
54 // an incomplete type a pointer or reference to an incomplete type, other
55 // than (cv) void*.
56 int kind;
57 if (const PointerType* IT = T->getAs<PointerType>()) {
58 T = IT->getPointeeType();
59 kind = 1;
60 } else if (const ReferenceType* IT = T->getAs<ReferenceType>()) {
61 T = IT->getPointeeType();
62 kind = 2;
63 } else
64 return false;
65
Douglas Gregor0966f352009-12-10 18:13:52 +000066 // Again as before
67 if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined())
68 return false;
69
Sebastian Redl491b84c2009-10-14 14:59:48 +000070 if (!T->isVoidType() && RequireCompleteType(Range.getBegin(), T,
Douglas Gregor0966f352009-12-10 18:13:52 +000071 PDiag(diag::err_incomplete_in_exception_spec) << kind << Range))
Sebastian Redl491b84c2009-10-14 14:59:48 +000072 return true;
Sebastian Redldced2262009-10-11 09:03:14 +000073
74 return false;
75}
76
77/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
78/// to member to a function with an exception specification. This means that
79/// it is invalid to add another level of indirection.
80bool Sema::CheckDistantExceptionSpec(QualType T) {
81 if (const PointerType *PT = T->getAs<PointerType>())
82 T = PT->getPointeeType();
83 else if (const MemberPointerType *PT = T->getAs<MemberPointerType>())
84 T = PT->getPointeeType();
85 else
86 return false;
87
88 const FunctionProtoType *FnT = T->getAs<FunctionProtoType>();
89 if (!FnT)
90 return false;
91
92 return FnT->hasExceptionSpec();
93}
94
95/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
96/// exception specifications. Exception specifications are equivalent if
97/// they allow exactly the same set of exception types. It does not matter how
98/// that is achieved. See C++ [except.spec]p2.
99bool Sema::CheckEquivalentExceptionSpec(
100 const FunctionProtoType *Old, SourceLocation OldLoc,
101 const FunctionProtoType *New, SourceLocation NewLoc) {
102 return CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec,
103 diag::note_previous_declaration,
104 Old, OldLoc, New, NewLoc);
105}
106
107/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
108/// exception specifications. Exception specifications are equivalent if
109/// they allow exactly the same set of exception types. It does not matter how
110/// that is achieved. See C++ [except.spec]p2.
111bool Sema::CheckEquivalentExceptionSpec(
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000112 const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
Sebastian Redldced2262009-10-11 09:03:14 +0000113 const FunctionProtoType *Old, SourceLocation OldLoc,
114 const FunctionProtoType *New, SourceLocation NewLoc) {
115 bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec();
116 bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec();
117 if (OldAny && NewAny)
118 return false;
119 if (OldAny || NewAny) {
120 Diag(NewLoc, DiagID);
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000121 if (NoteID.getDiagID() != 0)
Sebastian Redldced2262009-10-11 09:03:14 +0000122 Diag(OldLoc, NoteID);
123 return true;
124 }
125
126 bool Success = true;
127 // Both have a definite exception spec. Collect the first set, then compare
128 // to the second.
Sebastian Redl1219d152009-10-14 15:06:25 +0000129 llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes;
Sebastian Redldced2262009-10-11 09:03:14 +0000130 for (FunctionProtoType::exception_iterator I = Old->exception_begin(),
131 E = Old->exception_end(); I != E; ++I)
Sebastian Redl1219d152009-10-14 15:06:25 +0000132 OldTypes.insert(Context.getCanonicalType(*I).getUnqualifiedType());
Sebastian Redldced2262009-10-11 09:03:14 +0000133
134 for (FunctionProtoType::exception_iterator I = New->exception_begin(),
Sebastian Redl5db4d902009-10-11 09:11:23 +0000135 E = New->exception_end(); I != E && Success; ++I) {
Sebastian Redl1219d152009-10-14 15:06:25 +0000136 CanQualType TypePtr = Context.getCanonicalType(*I).getUnqualifiedType();
Sebastian Redl5db4d902009-10-11 09:11:23 +0000137 if(OldTypes.count(TypePtr))
138 NewTypes.insert(TypePtr);
139 else
140 Success = false;
141 }
Sebastian Redldced2262009-10-11 09:03:14 +0000142
Sebastian Redl5db4d902009-10-11 09:11:23 +0000143 Success = Success && OldTypes.size() == NewTypes.size();
Sebastian Redldced2262009-10-11 09:03:14 +0000144
145 if (Success) {
146 return false;
147 }
148 Diag(NewLoc, DiagID);
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000149 if (NoteID.getDiagID() != 0)
Sebastian Redldced2262009-10-11 09:03:14 +0000150 Diag(OldLoc, NoteID);
151 return true;
152}
153
154/// CheckExceptionSpecSubset - Check whether the second function type's
155/// exception specification is a subset (or equivalent) of the first function
156/// type. This is used by override and pointer assignment checks.
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000157bool Sema::CheckExceptionSpecSubset(
158 const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
Sebastian Redldced2262009-10-11 09:03:14 +0000159 const FunctionProtoType *Superset, SourceLocation SuperLoc,
160 const FunctionProtoType *Subset, SourceLocation SubLoc) {
161 // FIXME: As usual, we could be more specific in our error messages, but
162 // that better waits until we've got types with source locations.
163
164 if (!SubLoc.isValid())
165 SubLoc = SuperLoc;
166
167 // If superset contains everything, we're done.
168 if (!Superset->hasExceptionSpec() || Superset->hasAnyExceptionSpec())
169 return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
170
171 // It does not. If the subset contains everything, we've failed.
172 if (!Subset->hasExceptionSpec() || Subset->hasAnyExceptionSpec()) {
173 Diag(SubLoc, DiagID);
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000174 if (NoteID.getDiagID() != 0)
Sebastian Redldced2262009-10-11 09:03:14 +0000175 Diag(SuperLoc, NoteID);
176 return true;
177 }
178
179 // Neither contains everything. Do a proper comparison.
180 for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(),
181 SubE = Subset->exception_end(); SubI != SubE; ++SubI) {
182 // Take one type from the subset.
183 QualType CanonicalSubT = Context.getCanonicalType(*SubI);
Sebastian Redlc3a3b7b2009-10-14 14:38:54 +0000184 // Unwrap pointers and references so that we can do checks within a class
185 // hierarchy. Don't unwrap member pointers; they don't have hierarchy
186 // conversions on the pointee.
Sebastian Redldced2262009-10-11 09:03:14 +0000187 bool SubIsPointer = false;
188 if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>())
189 CanonicalSubT = RefTy->getPointeeType();
190 if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) {
191 CanonicalSubT = PtrTy->getPointeeType();
192 SubIsPointer = true;
193 }
194 bool SubIsClass = CanonicalSubT->isRecordType();
Douglas Gregora4923eb2009-11-16 21:35:15 +0000195 CanonicalSubT = CanonicalSubT.getLocalUnqualifiedType();
Sebastian Redldced2262009-10-11 09:03:14 +0000196
197 CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
198 /*DetectVirtual=*/false);
199
200 bool Contained = false;
201 // Make sure it's in the superset.
202 for (FunctionProtoType::exception_iterator SuperI =
203 Superset->exception_begin(), SuperE = Superset->exception_end();
204 SuperI != SuperE; ++SuperI) {
205 QualType CanonicalSuperT = Context.getCanonicalType(*SuperI);
206 // SubT must be SuperT or derived from it, or pointer or reference to
207 // such types.
208 if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>())
209 CanonicalSuperT = RefTy->getPointeeType();
210 if (SubIsPointer) {
211 if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>())
212 CanonicalSuperT = PtrTy->getPointeeType();
213 else {
214 continue;
215 }
216 }
Douglas Gregora4923eb2009-11-16 21:35:15 +0000217 CanonicalSuperT = CanonicalSuperT.getLocalUnqualifiedType();
Sebastian Redldced2262009-10-11 09:03:14 +0000218 // If the types are the same, move on to the next type in the subset.
219 if (CanonicalSubT == CanonicalSuperT) {
220 Contained = true;
221 break;
222 }
223
224 // Otherwise we need to check the inheritance.
225 if (!SubIsClass || !CanonicalSuperT->isRecordType())
226 continue;
227
228 Paths.clear();
229 if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths))
230 continue;
231
232 if (Paths.isAmbiguous(CanonicalSuperT))
233 continue;
234
John McCall6b2accb2010-02-10 09:31:12 +0000235 // Do this check from a context without privileges.
236 switch (CheckBaseClassAccess(SourceLocation(), false,
237 CanonicalSuperT, CanonicalSubT,
238 Paths.front(),
239 /*ForceCheck*/ true,
240 /*ForceUnprivileged*/ true,
241 ADK_quiet)) {
242 case AR_accessible: break;
243 case AR_inaccessible: continue;
244 case AR_dependent:
245 llvm_unreachable("access check dependent for unprivileged context");
246 break;
247 case AR_delayed:
248 llvm_unreachable("access check delayed in non-declaration");
249 break;
250 }
Sebastian Redldced2262009-10-11 09:03:14 +0000251
252 Contained = true;
253 break;
254 }
255 if (!Contained) {
256 Diag(SubLoc, DiagID);
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000257 if (NoteID.getDiagID() != 0)
Sebastian Redldced2262009-10-11 09:03:14 +0000258 Diag(SuperLoc, NoteID);
259 return true;
260 }
261 }
262 // We've run half the gauntlet.
263 return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
264}
265
266static bool CheckSpecForTypesEquivalent(Sema &S,
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000267 const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
Sebastian Redldced2262009-10-11 09:03:14 +0000268 QualType Target, SourceLocation TargetLoc,
269 QualType Source, SourceLocation SourceLoc)
270{
271 const FunctionProtoType *TFunc = GetUnderlyingFunction(Target);
272 if (!TFunc)
273 return false;
274 const FunctionProtoType *SFunc = GetUnderlyingFunction(Source);
275 if (!SFunc)
276 return false;
277
278 return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc,
279 SFunc, SourceLoc);
280}
281
282/// CheckParamExceptionSpec - Check if the parameter and return types of the
283/// two functions have equivalent exception specs. This is part of the
284/// assignment and override compatibility check. We do not check the parameters
285/// of parameter function pointers recursively, as no sane programmer would
286/// even be able to write such a function type.
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000287bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
Sebastian Redldced2262009-10-11 09:03:14 +0000288 const FunctionProtoType *Target, SourceLocation TargetLoc,
289 const FunctionProtoType *Source, SourceLocation SourceLoc)
290{
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000291 if (CheckSpecForTypesEquivalent(*this,
292 PDiag(diag::err_deep_exception_specs_differ) << 0, 0,
Sebastian Redldced2262009-10-11 09:03:14 +0000293 Target->getResultType(), TargetLoc,
294 Source->getResultType(), SourceLoc))
295 return true;
296
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000297 // We shouldn't even be testing this unless the arguments are otherwise
Sebastian Redldced2262009-10-11 09:03:14 +0000298 // compatible.
299 assert(Target->getNumArgs() == Source->getNumArgs() &&
300 "Functions have different argument counts.");
301 for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) {
Sebastian Redl37c38ec2009-10-14 16:09:29 +0000302 if (CheckSpecForTypesEquivalent(*this,
303 PDiag(diag::err_deep_exception_specs_differ) << 1, 0,
Sebastian Redldced2262009-10-11 09:03:14 +0000304 Target->getArgType(i), TargetLoc,
305 Source->getArgType(i), SourceLoc))
306 return true;
307 }
308 return false;
309}
310
311bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
312{
313 // First we check for applicability.
314 // Target type must be a function, function pointer or function reference.
315 const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType);
316 if (!ToFunc)
317 return false;
318
319 // SourceType must be a function or function pointer.
320 const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType());
321 if (!FromFunc)
322 return false;
323
324 // Now we've got the correct types on both sides, check their compatibility.
325 // This means that the source of the conversion can only throw a subset of
326 // the exceptions of the target, and any exception specs on arguments or
327 // return types must be equivalent.
328 return CheckExceptionSpecSubset(diag::err_incompatible_exception_specs,
329 0, ToFunc, From->getSourceRange().getBegin(),
330 FromFunc, SourceLocation());
331}
332
333bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
334 const CXXMethodDecl *Old) {
335 return CheckExceptionSpecSubset(diag::err_override_exception_spec,
336 diag::note_overridden_virtual_function,
337 Old->getType()->getAs<FunctionProtoType>(),
338 Old->getLocation(),
339 New->getType()->getAs<FunctionProtoType>(),
340 New->getLocation());
341}
342
343} // end namespace clang