clang API Documentation
00001 //===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file provides Sema routines for C++ exception specification testing. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "Sema.h" 00015 #include "clang/AST/CXXInheritance.h" 00016 #include "clang/AST/Expr.h" 00017 #include "clang/AST/ExprCXX.h" 00018 #include "clang/AST/TypeLoc.h" 00019 #include "clang/Lex/Preprocessor.h" 00020 #include "clang/Basic/Diagnostic.h" 00021 #include "clang/Basic/SourceManager.h" 00022 #include "llvm/ADT/SmallPtrSet.h" 00023 00024 namespace clang { 00025 00026 static const FunctionProtoType *GetUnderlyingFunction(QualType T) 00027 { 00028 if (const PointerType *PtrTy = T->getAs<PointerType>()) 00029 T = PtrTy->getPointeeType(); 00030 else if (const ReferenceType *RefTy = T->getAs<ReferenceType>()) 00031 T = RefTy->getPointeeType(); 00032 else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>()) 00033 T = MPTy->getPointeeType(); 00034 return T->getAs<FunctionProtoType>(); 00035 } 00036 00037 /// CheckSpecifiedExceptionType - Check if the given type is valid in an 00038 /// exception specification. Incomplete types, or pointers to incomplete types 00039 /// other than void are not allowed. 00040 bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) { 00041 00042 // This check (and the similar one below) deals with issue 437, that changes 00043 // C++ 9.2p2 this way: 00044 // Within the class member-specification, the class is regarded as complete 00045 // within function bodies, default arguments, exception-specifications, and 00046 // constructor ctor-initializers (including such things in nested classes). 00047 if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined()) 00048 return false; 00049 00050 // C++ 15.4p2: A type denoted in an exception-specification shall not denote 00051 // an incomplete type. 00052 if (RequireCompleteType(Range.getBegin(), T, 00053 PDiag(diag::err_incomplete_in_exception_spec) << /*direct*/0 << Range)) 00054 return true; 00055 00056 // C++ 15.4p2: A type denoted in an exception-specification shall not denote 00057 // an incomplete type a pointer or reference to an incomplete type, other 00058 // than (cv) void*. 00059 int kind; 00060 if (const PointerType* IT = T->getAs<PointerType>()) { 00061 T = IT->getPointeeType(); 00062 kind = 1; 00063 } else if (const ReferenceType* IT = T->getAs<ReferenceType>()) { 00064 T = IT->getPointeeType(); 00065 kind = 2; 00066 } else 00067 return false; 00068 00069 // Again as before 00070 if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined()) 00071 return false; 00072 00073 if (!T->isVoidType() && RequireCompleteType(Range.getBegin(), T, 00074 PDiag(diag::err_incomplete_in_exception_spec) << kind << Range)) 00075 return true; 00076 00077 return false; 00078 } 00079 00080 /// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer 00081 /// to member to a function with an exception specification. This means that 00082 /// it is invalid to add another level of indirection. 00083 bool Sema::CheckDistantExceptionSpec(QualType T) { 00084 if (const PointerType *PT = T->getAs<PointerType>()) 00085 T = PT->getPointeeType(); 00086 else if (const MemberPointerType *PT = T->getAs<MemberPointerType>()) 00087 T = PT->getPointeeType(); 00088 else 00089 return false; 00090 00091 const FunctionProtoType *FnT = T->getAs<FunctionProtoType>(); 00092 if (!FnT) 00093 return false; 00094 00095 return FnT->hasExceptionSpec(); 00096 } 00097 00098 bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { 00099 bool MissingExceptionSpecification = false; 00100 bool MissingEmptyExceptionSpecification = false; 00101 if (!CheckEquivalentExceptionSpec(PDiag(diag::err_mismatched_exception_spec), 00102 PDiag(diag::note_previous_declaration), 00103 Old->getType()->getAs<FunctionProtoType>(), 00104 Old->getLocation(), 00105 New->getType()->getAs<FunctionProtoType>(), 00106 New->getLocation(), 00107 &MissingExceptionSpecification, 00108 &MissingEmptyExceptionSpecification)) 00109 return false; 00110 00111 // The failure was something other than an empty exception 00112 // specification; return an error. 00113 if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification) 00114 return true; 00115 00116 // The new function declaration is only missing an empty exception 00117 // specification "throw()". If the throw() specification came from a 00118 // function in a system header that has C linkage, just add an empty 00119 // exception specification to the "new" declaration. This is an 00120 // egregious workaround for glibc, which adds throw() specifications 00121 // to many libc functions as an optimization. Unfortunately, that 00122 // optimization isn't permitted by the C++ standard, so we're forced 00123 // to work around it here. 00124 if (MissingEmptyExceptionSpecification && 00125 isa<FunctionProtoType>(New->getType()) && 00126 (Old->getLocation().isInvalid() || 00127 Context.getSourceManager().isInSystemHeader(Old->getLocation())) && 00128 Old->isExternC()) { 00129 const FunctionProtoType *NewProto 00130 = cast<FunctionProtoType>(New->getType()); 00131 QualType NewType = Context.getFunctionType(NewProto->getResultType(), 00132 NewProto->arg_type_begin(), 00133 NewProto->getNumArgs(), 00134 NewProto->isVariadic(), 00135 NewProto->getTypeQuals(), 00136 true, false, 0, 0, 00137 NewProto->getExtInfo()); 00138 New->setType(NewType); 00139 return false; 00140 } 00141 00142 if (MissingExceptionSpecification && isa<FunctionProtoType>(New->getType())) { 00143 const FunctionProtoType *NewProto 00144 = cast<FunctionProtoType>(New->getType()); 00145 const FunctionProtoType *OldProto 00146 = Old->getType()->getAs<FunctionProtoType>(); 00147 00148 // Update the type of the function with the appropriate exception 00149 // specification. 00150 QualType NewType = Context.getFunctionType(NewProto->getResultType(), 00151 NewProto->arg_type_begin(), 00152 NewProto->getNumArgs(), 00153 NewProto->isVariadic(), 00154 NewProto->getTypeQuals(), 00155 OldProto->hasExceptionSpec(), 00156 OldProto->hasAnyExceptionSpec(), 00157 OldProto->getNumExceptions(), 00158 OldProto->exception_begin(), 00159 NewProto->getExtInfo()); 00160 New->setType(NewType); 00161 00162 // If exceptions are disabled, suppress the warning about missing 00163 // exception specifications for new and delete operators. 00164 if (!getLangOptions().Exceptions) { 00165 switch (New->getDeclName().getCXXOverloadedOperator()) { 00166 case OO_New: 00167 case OO_Array_New: 00168 case OO_Delete: 00169 case OO_Array_Delete: 00170 if (New->getDeclContext()->isTranslationUnit()) 00171 return false; 00172 break; 00173 00174 default: 00175 break; 00176 } 00177 } 00178 00179 // Warn about the lack of exception specification. 00180 llvm::SmallString<128> ExceptionSpecString; 00181 llvm::raw_svector_ostream OS(ExceptionSpecString); 00182 OS << "throw("; 00183 bool OnFirstException = true; 00184 for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(), 00185 EEnd = OldProto->exception_end(); 00186 E != EEnd; 00187 ++E) { 00188 if (OnFirstException) 00189 OnFirstException = false; 00190 else 00191 OS << ", "; 00192 00193 OS << E->getAsString(Context.PrintingPolicy); 00194 } 00195 OS << ")"; 00196 OS.flush(); 00197 00198 SourceLocation AfterParenLoc; 00199 if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) { 00200 TypeLoc TL = TSInfo->getTypeLoc(); 00201 if (const FunctionTypeLoc *FTLoc = dyn_cast<FunctionTypeLoc>(&TL)) 00202 AfterParenLoc = PP.getLocForEndOfToken(FTLoc->getRParenLoc()); 00203 } 00204 00205 if (AfterParenLoc.isInvalid()) 00206 Diag(New->getLocation(), diag::warn_missing_exception_specification) 00207 << New << OS.str(); 00208 else { 00209 // FIXME: This will get more complicated with C++0x 00210 // late-specified return types. 00211 Diag(New->getLocation(), diag::warn_missing_exception_specification) 00212 << New << OS.str() 00213 << FixItHint::CreateInsertion(AfterParenLoc, " " + OS.str().str()); 00214 } 00215 00216 if (!Old->getLocation().isInvalid()) 00217 Diag(Old->getLocation(), diag::note_previous_declaration); 00218 00219 return false; 00220 } 00221 00222 Diag(New->getLocation(), diag::err_mismatched_exception_spec); 00223 Diag(Old->getLocation(), diag::note_previous_declaration); 00224 return true; 00225 } 00226 00227 /// CheckEquivalentExceptionSpec - Check if the two types have equivalent 00228 /// exception specifications. Exception specifications are equivalent if 00229 /// they allow exactly the same set of exception types. It does not matter how 00230 /// that is achieved. See C++ [except.spec]p2. 00231 bool Sema::CheckEquivalentExceptionSpec( 00232 const FunctionProtoType *Old, SourceLocation OldLoc, 00233 const FunctionProtoType *New, SourceLocation NewLoc) { 00234 return CheckEquivalentExceptionSpec( 00235 PDiag(diag::err_mismatched_exception_spec), 00236 PDiag(diag::note_previous_declaration), 00237 Old, OldLoc, New, NewLoc); 00238 } 00239 00240 /// CheckEquivalentExceptionSpec - Check if the two types have equivalent 00241 /// exception specifications. Exception specifications are equivalent if 00242 /// they allow exactly the same set of exception types. It does not matter how 00243 /// that is achieved. See C++ [except.spec]p2. 00244 bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, 00245 const PartialDiagnostic & NoteID, 00246 const FunctionProtoType *Old, 00247 SourceLocation OldLoc, 00248 const FunctionProtoType *New, 00249 SourceLocation NewLoc, 00250 bool *MissingExceptionSpecification, 00251 bool *MissingEmptyExceptionSpecification) { 00252 if (MissingExceptionSpecification) 00253 *MissingExceptionSpecification = false; 00254 00255 if (MissingEmptyExceptionSpecification) 00256 *MissingEmptyExceptionSpecification = false; 00257 00258 bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec(); 00259 bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec(); 00260 if (OldAny && NewAny) 00261 return false; 00262 if (OldAny || NewAny) { 00263 if (MissingExceptionSpecification && Old->hasExceptionSpec() && 00264 !New->hasExceptionSpec()) { 00265 // The old type has an exception specification of some sort, but 00266 // the new type does not. 00267 *MissingExceptionSpecification = true; 00268 00269 if (MissingEmptyExceptionSpecification && 00270 !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0) { 00271 // The old type has a throw() exception specification and the 00272 // new type has no exception specification, and the caller asked 00273 // to handle this itself. 00274 *MissingEmptyExceptionSpecification = true; 00275 } 00276 00277 return true; 00278 } 00279 00280 Diag(NewLoc, DiagID); 00281 if (NoteID.getDiagID() != 0) 00282 Diag(OldLoc, NoteID); 00283 return true; 00284 } 00285 00286 bool Success = true; 00287 // Both have a definite exception spec. Collect the first set, then compare 00288 // to the second. 00289 llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes; 00290 for (FunctionProtoType::exception_iterator I = Old->exception_begin(), 00291 E = Old->exception_end(); I != E; ++I) 00292 OldTypes.insert(Context.getCanonicalType(*I).getUnqualifiedType()); 00293 00294 for (FunctionProtoType::exception_iterator I = New->exception_begin(), 00295 E = New->exception_end(); I != E && Success; ++I) { 00296 CanQualType TypePtr = Context.getCanonicalType(*I).getUnqualifiedType(); 00297 if(OldTypes.count(TypePtr)) 00298 NewTypes.insert(TypePtr); 00299 else 00300 Success = false; 00301 } 00302 00303 Success = Success && OldTypes.size() == NewTypes.size(); 00304 00305 if (Success) { 00306 return false; 00307 } 00308 Diag(NewLoc, DiagID); 00309 if (NoteID.getDiagID() != 0) 00310 Diag(OldLoc, NoteID); 00311 return true; 00312 } 00313 00314 /// CheckExceptionSpecSubset - Check whether the second function type's 00315 /// exception specification is a subset (or equivalent) of the first function 00316 /// type. This is used by override and pointer assignment checks. 00317 bool Sema::CheckExceptionSpecSubset( 00318 const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, 00319 const FunctionProtoType *Superset, SourceLocation SuperLoc, 00320 const FunctionProtoType *Subset, SourceLocation SubLoc) { 00321 // FIXME: As usual, we could be more specific in our error messages, but 00322 // that better waits until we've got types with source locations. 00323 00324 if (!SubLoc.isValid()) 00325 SubLoc = SuperLoc; 00326 00327 // If superset contains everything, we're done. 00328 if (!Superset->hasExceptionSpec() || Superset->hasAnyExceptionSpec()) 00329 return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); 00330 00331 // It does not. If the subset contains everything, we've failed. 00332 if (!Subset->hasExceptionSpec() || Subset->hasAnyExceptionSpec()) { 00333 Diag(SubLoc, DiagID); 00334 if (NoteID.getDiagID() != 0) 00335 Diag(SuperLoc, NoteID); 00336 return true; 00337 } 00338 00339 // Neither contains everything. Do a proper comparison. 00340 for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(), 00341 SubE = Subset->exception_end(); SubI != SubE; ++SubI) { 00342 // Take one type from the subset. 00343 QualType CanonicalSubT = Context.getCanonicalType(*SubI); 00344 // Unwrap pointers and references so that we can do checks within a class 00345 // hierarchy. Don't unwrap member pointers; they don't have hierarchy 00346 // conversions on the pointee. 00347 bool SubIsPointer = false; 00348 if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>()) 00349 CanonicalSubT = RefTy->getPointeeType(); 00350 if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) { 00351 CanonicalSubT = PtrTy->getPointeeType(); 00352 SubIsPointer = true; 00353 } 00354 bool SubIsClass = CanonicalSubT->isRecordType(); 00355 CanonicalSubT = CanonicalSubT.getLocalUnqualifiedType(); 00356 00357 CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, 00358 /*DetectVirtual=*/false); 00359 00360 bool Contained = false; 00361 // Make sure it's in the superset. 00362 for (FunctionProtoType::exception_iterator SuperI = 00363 Superset->exception_begin(), SuperE = Superset->exception_end(); 00364 SuperI != SuperE; ++SuperI) { 00365 QualType CanonicalSuperT = Context.getCanonicalType(*SuperI); 00366 // SubT must be SuperT or derived from it, or pointer or reference to 00367 // such types. 00368 if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>()) 00369 CanonicalSuperT = RefTy->getPointeeType(); 00370 if (SubIsPointer) { 00371 if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>()) 00372 CanonicalSuperT = PtrTy->getPointeeType(); 00373 else { 00374 continue; 00375 } 00376 } 00377 CanonicalSuperT = CanonicalSuperT.getLocalUnqualifiedType(); 00378 // If the types are the same, move on to the next type in the subset. 00379 if (CanonicalSubT == CanonicalSuperT) { 00380 Contained = true; 00381 break; 00382 } 00383 00384 // Otherwise we need to check the inheritance. 00385 if (!SubIsClass || !CanonicalSuperT->isRecordType()) 00386 continue; 00387 00388 Paths.clear(); 00389 if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths)) 00390 continue; 00391 00392 if (Paths.isAmbiguous(CanonicalSuperT)) 00393 continue; 00394 00395 // Do this check from a context without privileges. 00396 switch (CheckBaseClassAccess(SourceLocation(), 00397 CanonicalSuperT, CanonicalSubT, 00398 Paths.front(), 00399 /*Diagnostic*/ 0, 00400 /*ForceCheck*/ true, 00401 /*ForceUnprivileged*/ true)) { 00402 case AR_accessible: break; 00403 case AR_inaccessible: continue; 00404 case AR_dependent: 00405 llvm_unreachable("access check dependent for unprivileged context"); 00406 break; 00407 case AR_delayed: 00408 llvm_unreachable("access check delayed in non-declaration"); 00409 break; 00410 } 00411 00412 Contained = true; 00413 break; 00414 } 00415 if (!Contained) { 00416 Diag(SubLoc, DiagID); 00417 if (NoteID.getDiagID() != 0) 00418 Diag(SuperLoc, NoteID); 00419 return true; 00420 } 00421 } 00422 // We've run half the gauntlet. 00423 return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); 00424 } 00425 00426 static bool CheckSpecForTypesEquivalent(Sema &S, 00427 const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, 00428 QualType Target, SourceLocation TargetLoc, 00429 QualType Source, SourceLocation SourceLoc) 00430 { 00431 const FunctionProtoType *TFunc = GetUnderlyingFunction(Target); 00432 if (!TFunc) 00433 return false; 00434 const FunctionProtoType *SFunc = GetUnderlyingFunction(Source); 00435 if (!SFunc) 00436 return false; 00437 00438 return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc, 00439 SFunc, SourceLoc); 00440 } 00441 00442 /// CheckParamExceptionSpec - Check if the parameter and return types of the 00443 /// two functions have equivalent exception specs. This is part of the 00444 /// assignment and override compatibility check. We do not check the parameters 00445 /// of parameter function pointers recursively, as no sane programmer would 00446 /// even be able to write such a function type. 00447 bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID, 00448 const FunctionProtoType *Target, SourceLocation TargetLoc, 00449 const FunctionProtoType *Source, SourceLocation SourceLoc) 00450 { 00451 if (CheckSpecForTypesEquivalent(*this, 00452 PDiag(diag::err_deep_exception_specs_differ) << 0, 00453 PDiag(), 00454 Target->getResultType(), TargetLoc, 00455 Source->getResultType(), SourceLoc)) 00456 return true; 00457 00458 // We shouldn't even be testing this unless the arguments are otherwise 00459 // compatible. 00460 assert(Target->getNumArgs() == Source->getNumArgs() && 00461 "Functions have different argument counts."); 00462 for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) { 00463 if (CheckSpecForTypesEquivalent(*this, 00464 PDiag(diag::err_deep_exception_specs_differ) << 1, 00465 PDiag(), 00466 Target->getArgType(i), TargetLoc, 00467 Source->getArgType(i), SourceLoc)) 00468 return true; 00469 } 00470 return false; 00471 } 00472 00473 bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) 00474 { 00475 // First we check for applicability. 00476 // Target type must be a function, function pointer or function reference. 00477 const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType); 00478 if (!ToFunc) 00479 return false; 00480 00481 // SourceType must be a function or function pointer. 00482 const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType()); 00483 if (!FromFunc) 00484 return false; 00485 00486 // Now we've got the correct types on both sides, check their compatibility. 00487 // This means that the source of the conversion can only throw a subset of 00488 // the exceptions of the target, and any exception specs on arguments or 00489 // return types must be equivalent. 00490 return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs), 00491 PDiag(), ToFunc, 00492 From->getSourceRange().getBegin(), 00493 FromFunc, SourceLocation()); 00494 } 00495 00496 bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, 00497 const CXXMethodDecl *Old) { 00498 return CheckExceptionSpecSubset(PDiag(diag::err_override_exception_spec), 00499 PDiag(diag::note_overridden_virtual_function), 00500 Old->getType()->getAs<FunctionProtoType>(), 00501 Old->getLocation(), 00502 New->getType()->getAs<FunctionProtoType>(), 00503 New->getLocation()); 00504 } 00505 00506 } // end namespace clang