diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/ASTContext.cpp | 16 | ||||
-rw-r--r-- | lib/AST/ASTImporter.cpp | 21 | ||||
-rw-r--r-- | lib/AST/DeclPrinter.cpp | 20 | ||||
-rw-r--r-- | lib/AST/DumpXML.cpp | 5 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 2 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 2 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 71 | ||||
-rw-r--r-- | lib/AST/TypePrinter.cpp | 18 | ||||
-rw-r--r-- | lib/Analysis/CFG.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGCall.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGException.cpp | 7 | ||||
-rw-r--r-- | lib/CodeGen/CGExprCXX.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 11 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 184 | ||||
-rw-r--r-- | lib/Sema/SemaExceptionSpec.cpp | 245 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 20 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 17 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 21 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 13 |
22 files changed, 528 insertions, 183 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index fcfd230de0..c128ce598b 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1909,7 +1909,7 @@ ASTContext::getFunctionType(QualType ResultTy, // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; - FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI); + FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI, this); void *InsertPos = 0; if (FunctionProtoType *FTP = @@ -1953,14 +1953,20 @@ ASTContext::getFunctionType(QualType ResultTy, // FunctionProtoType objects are allocated with extra bytes after them // for two variable size arrays (for parameter and exception types) at the - // end of them. + // end of them. Instead of the exception types, there could be a noexcept + // expression and a context pointer. size_t Size = sizeof(FunctionProtoType) + - NumArgs * sizeof(QualType) + - EPI.NumExceptions * sizeof(QualType); + NumArgs * sizeof(QualType); + if (EPI.ExceptionSpecType == EST_Dynamic) + Size += EPI.NumExceptions * sizeof(QualType); + else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { + Size += sizeof(Expr*) + sizeof(ASTContext*); + } FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment); FunctionProtoType::ExtProtoInfo newEPI = EPI; newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv); - new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, newEPI); + new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, newEPI, + this); Types.push_back(FTP); FunctionProtoTypes.InsertNode(FTP, InsertPos); return QualType(FTP, 0); diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index b00c78827f..895f442eac 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -521,16 +521,21 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } if (Proto1->isVariadic() != Proto2->isVariadic()) return false; - if (Proto1->hasExceptionSpec() != Proto2->hasExceptionSpec()) + if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType()) return false; - if (Proto1->hasAnyExceptionSpec() != Proto2->hasAnyExceptionSpec()) - return false; - if (Proto1->getNumExceptions() != Proto2->getNumExceptions()) - return false; - for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) { + if (Proto1->getExceptionSpecType() == EST_Dynamic) { + if (Proto1->getNumExceptions() != Proto2->getNumExceptions()) + return false; + for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Proto1->getExceptionType(I), + Proto2->getExceptionType(I))) + return false; + } + } else if (Proto1->getExceptionSpecType() == EST_ComputedNoexcept) { if (!IsStructurallyEquivalent(Context, - Proto1->getExceptionType(I), - Proto2->getExceptionType(I))) + Proto1->getNoexceptExpr(), + Proto2->getNoexceptExpr())) return false; } if (Proto1->getTypeQuals() != Proto2->getTypeQuals()) diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index c6ae128e42..2781632384 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -412,22 +412,32 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (TypeQuals & Qualifiers::Restrict) Proto += " restrict"; } - - if (FT && FT->hasExceptionSpec()) { + + if (FT && FT->hasDynamicExceptionSpec()) { Proto += " throw("; - if (FT->hasAnyExceptionSpec()) + if (FT->getExceptionSpecType() == EST_MSAny) Proto += "..."; else for (unsigned I = 0, N = FT->getNumExceptions(); I != N; ++I) { if (I) Proto += ", "; - - + std::string ExceptionType; FT->getExceptionType(I).getAsStringInternal(ExceptionType, SubPolicy); Proto += ExceptionType; } Proto += ")"; + } else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) { + Proto += " noexcept"; + if (FT->getExceptionSpecType() == EST_ComputedNoexcept) { + Proto += "("; + llvm::raw_string_ostream EOut(Proto); + FT->getNoexceptExpr()->printPretty(EOut, Context, 0, SubPolicy, + Indentation); + EOut.flush(); + Proto += EOut.str(); + Proto += ")"; + } } if (D->hasAttr<NoReturnAttr>()) diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp index 9d828fcfb8..9a34722aa5 100644 --- a/lib/AST/DumpXML.cpp +++ b/lib/AST/DumpXML.cpp @@ -975,15 +975,16 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, dispatch(*I); pop(); - if (T->hasExceptionSpec()) { + if (T->hasDynamicExceptionSpec()) { push("exception_specifiers"); - setFlag("any", T->hasAnyExceptionSpec()); + setFlag("any", T->getExceptionSpecType() == EST_MSAny); completeAttrs(); for (FunctionProtoType::exception_iterator I = T->exception_begin(), E = T->exception_end(); I != E; ++I) dispatch(*I); pop(); } + // FIXME: noexcept specifier } void visitTemplateSpecializationTypeChildren(TemplateSpecializationType *T) { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 4793b114ef..1c7807e6d2 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1659,7 +1659,7 @@ static Expr::CanThrowResult CanCalleeThrow(const Decl *D, if (!FT) return Expr::CT_Can; - return FT->hasEmptyExceptionSpec() ? Expr::CT_Cannot : Expr::CT_Can; + return FT->isNothrow() ? Expr::CT_Cannot : Expr::CT_Can; } static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) { diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 966c1fe6a7..fd94dd108d 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -102,7 +102,7 @@ void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray, bool CXXNewExpr::shouldNullCheckAllocation() const { return getOperatorNew()->getType()-> - castAs<FunctionProtoType>()->hasNonThrowingExceptionSpec(); + castAs<FunctionProtoType>()->isNothrow(); } // CXXDeleteExpr diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index eea08f6242..eb5254e96e 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -21,6 +21,7 @@ #include "clang/AST/PrettyPrinter.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/Specifiers.h" +#include "llvm/ADT/APSInt.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -1165,7 +1166,8 @@ llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) { FunctionProtoType::FunctionProtoType(QualType result, const QualType *args, unsigned numArgs, QualType canonical, - const ExtProtoInfo &epi) + const ExtProtoInfo &epi, + const ASTContext *context) : FunctionType(FunctionProto, result, epi.Variadic, epi.TypeQuals, epi.RefQualifier, canonical, result->isDependentType(), @@ -1173,8 +1175,7 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args, result->containsUnexpandedParameterPack(), epi.ExtInfo), NumArgs(numArgs), NumExceptions(epi.NumExceptions), - HasExceptionSpec(isDynamicExceptionSpec(epi.ExceptionSpecType)), - HasAnyExceptionSpec(epi.ExceptionSpecType == EST_DynamicAny) + ExceptionSpecType(epi.ExceptionSpecType) { // Fill in the trailing argument array. QualType *argSlot = reinterpret_cast<QualType*>(this+1); @@ -1187,20 +1188,54 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args, argSlot[i] = args[i]; } - - // Fill in the exception array. - QualType *exnSlot = argSlot + numArgs; - for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) { - if (epi.Exceptions[i]->isDependentType()) - setDependent(); - if (epi.Exceptions[i]->containsUnexpandedParameterPack()) - setContainsUnexpandedParameterPack(); + if (getExceptionSpecType() == EST_Dynamic) { + // Fill in the exception array. + QualType *exnSlot = argSlot + numArgs; + for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) { + if (epi.Exceptions[i]->isDependentType()) + setDependent(); - exnSlot[i] = epi.Exceptions[i]; + if (epi.Exceptions[i]->containsUnexpandedParameterPack()) + setContainsUnexpandedParameterPack(); + + exnSlot[i] = epi.Exceptions[i]; + } + } else if (getExceptionSpecType() == EST_ComputedNoexcept) { + // Store the noexcept expression and context. + Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + numArgs); + *noexSlot = epi.NoexceptExpr; + const ASTContext **contextSlot = const_cast<const ASTContext**>( + reinterpret_cast<ASTContext**>(noexSlot + 1)); + *contextSlot = context; } } +FunctionProtoType::NoexceptResult +FunctionProtoType::getNoexceptSpec() const { + ExceptionSpecificationType est = getExceptionSpecType(); + if (est == EST_BasicNoexcept) + return NR_Nothrow; + + if (est != EST_ComputedNoexcept) + return NR_NoNoexcept; + + Expr *noexceptExpr = getNoexceptExpr(); + if (!noexceptExpr) + return NR_BadNoexcept; + if (noexceptExpr->isValueDependent()) + return NR_Dependent; + + llvm::APSInt value; + ASTContext& ctx = const_cast<ASTContext&>(*getContext()); + bool isICE = noexceptExpr->isIntegerConstantExpr(value, ctx, 0, + /*evaluated*/false); + (void)isICE; + assert(isICE && "AST should not contain bad noexcept expressions."); + + return value.getBoolValue() ? NR_Nothrow : NR_Throw; +} + bool FunctionProtoType::isTemplateVariadic() const { for (unsigned ArgIdx = getNumArgs(); ArgIdx; --ArgIdx) if (isa<PackExpansionType>(getArgType(ArgIdx - 1))) @@ -1211,23 +1246,27 @@ bool FunctionProtoType::isTemplateVariadic() const { void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, const QualType *ArgTys, unsigned NumArgs, - const ExtProtoInfo &epi) { + const ExtProtoInfo &epi, + const ASTContext *Context) { ID.AddPointer(Result.getAsOpaquePtr()); for (unsigned i = 0; i != NumArgs; ++i) ID.AddPointer(ArgTys[i].getAsOpaquePtr()); ID.AddBoolean(epi.Variadic); ID.AddInteger(epi.TypeQuals); ID.AddInteger(epi.RefQualifier); - if (isDynamicExceptionSpec(epi.ExceptionSpecType)) { - ID.AddBoolean(epi.ExceptionSpecType == EST_DynamicAny); + ID.AddInteger(epi.ExceptionSpecType); + if (epi.ExceptionSpecType == EST_Dynamic) { for (unsigned i = 0; i != epi.NumExceptions; ++i) ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr()); + } else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){ + epi.NoexceptExpr->Profile(ID, *Context, true); } epi.ExtInfo.Profile(ID); } void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getResultType(), arg_type_begin(), NumArgs, getExtProtoInfo()); + Profile(ID, getResultType(), arg_type_begin(), NumArgs, getExtProtoInfo(), + getContext()); } QualType TypedefType::desugar() const { diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 254f46337e..d0267caabd 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -421,12 +421,12 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T, S += " &&"; break; } - - if (T->hasExceptionSpec()) { + + if (T->hasDynamicExceptionSpec()) { S += " throw("; - if (T->hasAnyExceptionSpec()) + if (T->getExceptionSpecType() == EST_MSAny) S += "..."; - else + else for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) { if (I) S += ", "; @@ -436,6 +436,16 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T, S += ExceptionType; } S += ")"; + } else if (isNoexceptExceptionSpec(T->getExceptionSpecType())) { + S += " noexcept"; + if (T->getExceptionSpecType() == EST_ComputedNoexcept) { + S += "("; + llvm::raw_string_ostream EOut(S); + T->getNoexceptExpr()->printPretty(EOut, 0, Policy); + EOut.flush(); + S += EOut.str(); + S += ")"; + } } print(T->getResultType(), S); diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index ca7469f677..8d27c0cc49 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -1128,7 +1128,7 @@ static bool CanThrow(Expr *E) { const FunctionType *FT = Ty->getAs<FunctionType>(); if (FT) { if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) - if (Proto->hasEmptyExceptionSpec()) + if (Proto->isNothrow()) return false; } return true; diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 158e3a3a2c..d72e6dc429 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -709,7 +709,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, FuncAttrs |= llvm::Attribute::NoUnwind; else if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) { const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>(); - if (FPT && FPT->hasEmptyExceptionSpec()) + if (FPT && FPT->isNothrow()) FuncAttrs |= llvm::Attribute::NoUnwind; } diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 0b248bd783..f05bc700b4 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -449,9 +449,8 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { if (Proto == 0) return; - assert(!Proto->hasAnyExceptionSpec() && "function with parameter pack"); - - if (!Proto->hasExceptionSpec()) + // FIXME: What about noexcept? + if (!Proto->hasDynamicExceptionSpec()) return; unsigned NumExceptions = Proto->getNumExceptions(); @@ -477,7 +476,7 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { if (Proto == 0) return; - if (!Proto->hasExceptionSpec()) + if (!Proto->hasDynamicExceptionSpec()) return; EHStack.popFilter(); diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 0ca024059c..c9c8a6a35d 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -982,7 +982,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { // exception spec; for this part, we inline // CXXNewExpr::shouldNullCheckAllocation()) and we have an // interesting initializer. - bool nullCheck = allocatorType->hasNonThrowingExceptionSpec() && + bool nullCheck = allocatorType->isNothrow() && !(allocType->isPODType() && !E->hasInitializer()); llvm::BasicBlock *nullCheckBB = 0; diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 7b11e92d97..2cd2398157 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -2042,6 +2042,11 @@ Parser::MaybeParseExceptionSpecification(SourceRange &SpecificationRange, SourceLocation LParenLoc = ConsumeParen(); NoexceptType = EST_ComputedNoexcept; NoexceptExpr = ParseConstantExpression(); + // The argument must be contextually convertible to bool. We use + // ActOnBooleanCondition for this purpose. + if (!NoexceptExpr.isInvalid()) + NoexceptExpr = Actions.ActOnBooleanCondition(getCurScope(), KeywordLoc, + NoexceptExpr.get()); SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); NoexceptRange = SourceRange(KeywordLoc, RParenLoc); } else { @@ -2090,7 +2095,7 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification( if (!Tok.is(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "throw"; SpecificationRange.setEnd(SpecificationRange.getBegin()); - return EST_Dynamic; + return EST_DynamicNone; } SourceLocation LParenLoc = ConsumeParen(); @@ -2102,7 +2107,7 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification( Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec); SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); SpecificationRange.setEnd(RParenLoc); - return EST_DynamicAny; + return EST_MSAny; } // Parse the sequence of type-ids. @@ -2132,7 +2137,7 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification( } SpecificationRange.setEnd(MatchRHSPunctuation(tok::r_paren, LParenLoc)); - return EST_Dynamic; + return Exceptions.empty() ? EST_DynamicNone : EST_Dynamic; } /// ParseTrailingReturnType - Parse a trailing return type on a new-style diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 10993276c6..68b599bd37 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -1238,6 +1238,16 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() { if (!SkipUntil(tok::r_paren)) return TPResult::Error(); } + if (Tok.is(tok::kw_noexcept)) { + ConsumeToken(); + // Possibly an expression as well. + if (Tok.is(tok::l_paren)) { + // Find the matching rparen. + ConsumeParen(); + if (!SkipUntil(tok::r_paren)) + return TPResult::Error(); + } + } return TPResult::Ambiguous(); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c9678644cb..3b2a062162 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1552,8 +1552,8 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, mergeParamDeclAttributes(*ni, *oi, Context); } -/// MergeVarDecl - We parsed a variable 'New' which has the same name and scope -/// as a previous declaration 'Old'. Figure out how to merge their types, +/// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and +/// scope as a previous declaration 'Old'. Figure out how to merge their types, /// emitting diagnostics as appropriate. /// /// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back @@ -1570,8 +1570,10 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) { if (AT && !AT->isDeduced()) { // We don't know what the new type is until the initializer is attached. return; - } else if (Context.hasSameType(New->getType(), Old->getType())) - return; + } else if (Context.hasSameType(New->getType(), Old->getType())) { + // These could still be something that needs exception specs checked. + return MergeVarDeclExceptionSpecs(New, Old); + } // C++ [basic.link]p10: // [...] the types specified by all declarations referring to a given // object or function shall be identical, except that declarations for an diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 2bce585dd2..f6551054c1 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -383,6 +383,48 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { return Invalid; } +/// \brief Merge the exception specifications of two variable declarations. +/// +/// This is called when there's a redeclaration of a VarDecl. The function +/// checks if the redeclaration might have an exception specification and +/// validates compatibility and merges the specs if necessary. +void Sema::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) { + // Shortcut if exceptions are disabled. + if (!getLangOptions().CXXExceptions) + return; + + assert(Context.hasSameType(New->getType(), Old->getType()) && + "Should only be called if types are otherwise the same."); + + QualType NewType = New->getType(); + QualType OldType = Old->getType(); + + // We're only interested in pointers and references to functions, as well + // as pointers to member functions. + if (const ReferenceType *R = NewType->getAs<ReferenceType>()) { + NewType = R->getPointeeType(); + OldType = OldType->getAs<ReferenceType>()->getPointeeType(); + } else if (const PointerType *P = NewType->getAs<PointerType>()) { + NewType = P->getPointeeType(); + OldType = OldType->getAs<PointerType>()->getPointeeType(); + } else if (const MemberPointerType *M = NewType->getAs<MemberPointerType>()) { + NewType = M->getPointeeType(); + OldType = OldType->getAs<MemberPointerType>()->getPointeeType(); + } + + if (!NewType->isFunctionProtoType()) + return; + + // There's lots of special cases for functions. For function pointers, system + // libraries are hopefully not as broken so that we don't need these + // workarounds. + if (CheckEquivalentExceptionSpec( + OldType->getAs<FunctionProtoType>(), Old->getLocation(), + NewType->getAs<FunctionProtoType>(), New->getLocation())) { + New->setInvalidDecl(); + } +} + /// CheckCXXDefaultArguments - Verify that the default arguments for a /// function declaration are well-formed according to C++ /// [dcl.fct.default]. @@ -2978,53 +3020,101 @@ namespace { /// implicitly-declared special member functions. class ImplicitExceptionSpecification { ASTContext &Context; - bool AllowsAllExceptions; + // We order exception specifications thus: + // noexcept is the most restrictive, but is only used in C++0x. + // throw() comes next. + // Then a throw(collected exceptions) + // Finally no specification. + // throw(...) is used instead if any called function uses it. + ExceptionSpecificationType ComputedEST; llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen; llvm::SmallVector<QualType, 4> Exceptions; - + + void ClearExceptions() { + ExceptionsSeen.clear(); + Exceptions.clear(); + } + public: explicit ImplicitExceptionSpecification(ASTContext &Context) - : Context(Context), AllowsAllExceptions(false) { } - - /// \brief Whether the special member function should have any - /// exception specification at all. - bool hasExceptionSpecification() const { - return !AllowsAllExceptions; + : Context(Context), ComputedEST(EST_BasicNoexcept) { + if (!Context.getLangOptions().CPlusPlus0x) + ComputedEST = EST_DynamicNone; } - - /// \brief Whether the special member function should have a - /// throw(...) exception specification (a Microsoft extension). - bool hasAnyExceptionSpecification() const { - return false; + + /// \brief Get the computed exception specification type. + ExceptionSpecificationType getExceptionSpecType() const { + assert(ComputedEST != EST_ComputedNoexcept && + "noexcept(expr) should not be a possible result"); + return ComputedEST; } - + /// \brief The number of exceptions in the exception specification. unsigned size() const { return Exceptions.size(); } - + /// \brief The set of exceptions in the exception specification. const QualType *data() const { return Exceptions.data(); } - - /// \brief Note that + + /// \brief Integrate another called method into the collected data. void CalledDecl(CXXMethodDecl *Method) { - // If we already know that we allow all exceptions, do nothing. - if (AllowsAllExceptions || !Method) + // If we have an MSAny spec already, don't bother. + if (!Method || ComputedEST == EST_MSAny) return; - + const FunctionProtoType *Proto = Method->getType()->getAs<FunctionProtoType>(); - + + ExceptionSpecificationType EST = Proto->getExceptionSpecType(); + // If this function can throw any exceptions, make a note of that. - if (!Proto->hasExceptionSpec() || Proto->hasAnyExceptionSpec()) { - AllowsAllExceptions = true; - ExceptionsSeen.clear(); - Exceptions.clear(); + if (EST == EST_MSAny || EST == EST_None) { + ClearExceptions(); + ComputedEST = EST; return; } - + + // If this function has a basic noexcept, it doesn't affect the outcome. + if (EST == EST_BasicNoexcept) + return; + + // If we have a throw-all spec at this point, ignore the function. + if (ComputedEST == EST_None) + return; + + // If we're still at noexcept(true) and there's a nothrow() callee, + // change to that specification. + if (EST == EST_DynamicNone) { + if (ComputedEST == EST_BasicNoexcept) + ComputedEST = EST_DynamicNone; + return; + } + + // Check out noexcept specs. + if (EST == EST_ComputedNoexcept) { + FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec(); + assert(NR != FunctionProtoType::NR_NoNoexcept && + "Must have noexcept result for EST_ComputedNoexcept."); + assert(NR != FunctionProtoType::NR_Dependent && + "Should not generate implicit declarations for dependent cases, " + "and don't know how to handle them anyway."); + + // noexcept(false) -> no spec on the new function + if (NR == FunctionProtoType::NR_Throw) { + ClearExceptions(); + ComputedEST = EST_None; + } + // noexcept(true) won't change anything either. + return; + } + + assert(EST == EST_Dynamic && "EST case not considered earlier."); + assert(ComputedEST != EST_None && + "Shouldn't collect exceptions when throw-all is guaranteed."); + ComputedEST = EST_Dynamic; // Record the exceptions in this function's exception specification. for (FunctionProtoType::exception_iterator E = Proto->exception_begin(), EEnd = Proto->exception_end(); - E != EEnd; ++E) + E != EEnd; ++E) if (ExceptionsSeen.insert(Context.getCanonicalType(*E))) Exceptions.push_back(*E); } @@ -4672,7 +4762,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( // exception-specification. [...] ImplicitExceptionSpecification ExceptSpec(Context); - // Direct base-class destructors. + // Direct base-class constructors. for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(), BEnd = ClassDecl->bases_end(); B != BEnd; ++B) { @@ -4688,8 +4778,8 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( ExceptSpec.CalledDecl(Constructor); } } - - // Virtual base-class destructors. + + // Virtual base-class constructors. for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(), BEnd = ClassDecl->vbases_end(); B != BEnd; ++B) { @@ -4702,8 +4792,8 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( ExceptSpec.CalledDecl(Constructor); } } - - // Field destructors. + + // Field constructors. for (RecordDecl::field_iterator F = ClassDecl->field_begin(), FEnd = ClassDecl->field_end(); F != FEnd; ++F) { @@ -4720,9 +4810,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( } FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = ExceptSpec.hasExceptionSpecification() ? - (ExceptSpec.hasAnyExceptionSpecification() ? EST_DynamicAny : EST_Dynamic) : - EST_None; + EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType(); EPI.NumExceptions = ExceptSpec.size(); EPI.Exceptions = ExceptSpec.data(); @@ -4997,16 +5085,14 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { ExceptSpec.CalledDecl( LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl()))); } - + // Create the actual destructor declaration. FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = ExceptSpec.hasExceptionSpecification() ? - (ExceptSpec.hasAnyExceptionSpecification() ? EST_DynamicAny : EST_Dynamic) : - EST_None; + EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType(); EPI.NumExceptions = ExceptSpec.size(); EPI.Exceptions = ExceptSpec.data(); QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, EPI); - + CanQualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); SourceLocation ClassLoc = ClassDecl->getLocation(); @@ -5014,9 +5100,9 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { = Context.DeclarationNames.getCXXDestructorName(ClassType); DeclarationNameInfo NameInfo(Name, ClassLoc); CXXDestructorDecl *Destructor - = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Ty, 0, - /*isInline=*/true, - /*isImplicitlyDeclared=*/true); + = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Ty, 0, + /*isInline=*/true, |