aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Redl <sebastian.redl@getdesigned.at>2011-03-12 11:50:43 +0000
committerSebastian Redl <sebastian.redl@getdesigned.at>2011-03-12 11:50:43 +0000
commit60618fa7f88d5162bb5b40988b6b38d4d75d6fc6 (patch)
tree21a6d213d2956ce39ff900b79ff7a2275eea5b76
parent796aa443ab5ed036f42ef33fed629e1b4b34871b (diff)
Propagate the new exception information to FunctionProtoType.
Change the interface to expose the new information and deal with the enormous fallout. Introduce the new ExceptionSpecificationType value EST_DynamicNone to more easily deal with empty throw specifications. Update the tests for noexcept and fix the various bugs uncovered, such as lack of tentative parsing support. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127537 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/Type.h91
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--include/clang/Basic/ExceptionSpecificationType.h7
-rw-r--r--include/clang/Sema/Sema.h6
-rw-r--r--lib/AST/ASTContext.cpp16
-rw-r--r--lib/AST/ASTImporter.cpp21
-rw-r--r--lib/AST/DeclPrinter.cpp20
-rw-r--r--lib/AST/DumpXML.cpp5
-rw-r--r--lib/AST/Expr.cpp2
-rw-r--r--lib/AST/ExprCXX.cpp2
-rw-r--r--lib/AST/Type.cpp71
-rw-r--r--lib/AST/TypePrinter.cpp18
-rw-r--r--lib/Analysis/CFG.cpp2
-rw-r--r--lib/CodeGen/CGCall.cpp2
-rw-r--r--lib/CodeGen/CGException.cpp7
-rw-r--r--lib/CodeGen/CGExprCXX.cpp2
-rw-r--r--lib/Parse/ParseDeclCXX.cpp11
-rw-r--r--lib/Parse/ParseTentative.cpp10
-rw-r--r--lib/Sema/SemaDecl.cpp10
-rw-r--r--lib/Sema/SemaDeclCXX.cpp184
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp245
-rw-r--r--lib/Sema/SemaExprCXX.cpp12
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp20
-rw-r--r--lib/Sema/SemaType.cpp17
-rw-r--r--lib/Serialization/ASTReader.cpp21
-rw-r--r--lib/Serialization/ASTWriter.cpp13
-rw-r--r--test/CXX/except/except.spec/p1.cpp29
-rw-r--r--test/CXX/except/except.spec/p2-dynamic-types.cpp34
-rw-r--r--test/CXX/except/except.spec/p2-places.cpp63
-rw-r--r--test/CXX/except/except.spec/p3.cpp94
-rw-r--r--test/CXX/except/except.spec/p5-pointers.cpp85
-rw-r--r--test/CXX/except/except.spec/p5-virtual.cpp96
-rw-r--r--test/SemaCXX/exception-spec.cpp193
33 files changed, 997 insertions, 414 deletions
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 713316f146..6d5ca71ed4 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -2430,19 +2430,17 @@ private:
}
FunctionProtoType(QualType result, const QualType *args, unsigned numArgs,
- QualType canonical, const ExtProtoInfo &epi);
+ QualType canonical, const ExtProtoInfo &epi,
+ const ASTContext *Context);
/// NumArgs - The number of arguments this function has, not counting '...'.
unsigned NumArgs : 20;
/// NumExceptions - The number of types in the exception spec, if any.
- unsigned NumExceptions : 10;
+ unsigned NumExceptions : 9;
- /// HasExceptionSpec - Whether this function has an exception spec at all.
- unsigned HasExceptionSpec : 1;
-
- /// HasAnyExceptionSpec - Whether this function has a throw(...) spec.
- unsigned HasAnyExceptionSpec : 1;
+ /// ExceptionSpecType - The type of exception specification this function has.
+ unsigned ExceptionSpecType : 3;
/// ArgInfo - There is an variable size array after the class in memory that
/// holds the argument types.
@@ -2450,6 +2448,19 @@ private:
/// Exceptions - There is another variable size array after ArgInfo that
/// holds the exception types.
+ /// NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing
+ /// to the expression in the noexcept() specifier.
+
+ /// Context - If there is a NoexceptExpr, we need to store a pointer to the
+ /// ASTContext as well. We do it right after NoexceptExpr.
+
+ const ASTContext *getContext() const {
+ // Context sits after NoexceptExpr, one pointer past where the arguments end
+ if(getExceptionSpecType() == EST_ComputedNoexcept)
+ return *(reinterpret_cast<const ASTContext *const *>(arg_type_end()) + 1);
+ return 0;
+ }
+
friend class ASTContext; // ASTContext creates these.
public:
@@ -2463,36 +2474,66 @@ public:
ExtProtoInfo EPI;
EPI.ExtInfo = getExtInfo();
EPI.Variadic = isVariadic();
- EPI.ExceptionSpecType = hasExceptionSpec() ?
- (hasAnyExceptionSpec() ? EST_DynamicAny : EST_Dynamic) : EST_None;
+ EPI.ExceptionSpecType = getExceptionSpecType();
EPI.TypeQuals = static_cast<unsigned char>(getTypeQuals());
EPI.RefQualifier = getRefQualifier();
- EPI.NumExceptions = NumExceptions;
- EPI.Exceptions = exception_begin();
+ if (EPI.ExceptionSpecType == EST_Dynamic) {
+ EPI.NumExceptions = NumExceptions;
+ EPI.Exceptions = exception_begin();
+ } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
+ EPI.NoexceptExpr = getNoexceptExpr();
+ }
return EPI;
}
- bool hasExceptionSpec() const { return HasExceptionSpec; }
- bool hasAnyExceptionSpec() const { return HasAnyExceptionSpec; }
+ /// \brief Get the kind of exception specification on this function.
+ ExceptionSpecificationType getExceptionSpecType() const {
+ return static_cast<ExceptionSpecificationType>(ExceptionSpecType);
+ }
+ /// \brief Return whether this function has any kind of exception spec.
+ bool hasExceptionSpec() const {
+ return getExceptionSpecType() != EST_None;
+ }
+ /// \brief Return whether this function has a dynamic (throw) exception spec.
+ bool hasDynamicExceptionSpec() const {
+ return isDynamicExceptionSpec(getExceptionSpecType());
+ }
+ /// \brief Return whther this function has a noexcept exception spec.
+ bool hasNoexceptExceptionSpec() const {
+ return isNoexceptExceptionSpec(getExceptionSpecType());
+ }
+ /// \brief Result type of getNoexceptSpec().
+ enum NoexceptResult {
+ NR_NoNoexcept, ///< There is no noexcept specifier.
+ NR_BadNoexcept, ///< The noexcept specifier has a bad expression.
+ NR_Dependent, ///< The noexcept specifier is dependent.
+ NR_Throw, ///< The noexcept specifier evaluates to false.
+ NR_Nothrow ///< The noexcept specifier evaluates to true.
+ };
+ /// \brief Get the meaning of the noexcept spec on this function, if any.
+ NoexceptResult getNoexceptSpec() const;
unsigned getNumExceptions() const { return NumExceptions; }
QualType getExceptionType(unsigned i) const {
assert(i < NumExceptions && "Invalid exception number!");
return exception_begin()[i];
}
- bool hasEmptyExceptionSpec() const {
- return hasExceptionSpec() && !hasAnyExceptionSpec() &&
- getNumExceptions() == 0;
+ Expr *getNoexceptExpr() const {
+ if (getExceptionSpecType() != EST_ComputedNoexcept)
+ return 0;
+ // NoexceptExpr sits where the arguments end.
+ return *reinterpret_cast<Expr *const *>(arg_type_end());
}
-
- /// \brief Returns true if this function type has a non-throwing
- /// exception-specification.
- bool hasNonThrowingExceptionSpec() const {
- // FIXME: this needs to be updated for C++0x.
- return hasEmptyExceptionSpec();
+ bool isNothrow() const {
+ ExceptionSpecificationType EST = getExceptionSpecType();
+ if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
+ return true;
+ if (EST != EST_ComputedNoexcept)
+ return false;
+ return getNoexceptSpec() == NR_Nothrow;
}
using FunctionType::isVariadic;
-
+
/// \brief Determines whether this function prototype contains a
/// parameter pack at the end.
///
@@ -2521,6 +2562,8 @@ public:
return arg_type_end();
}
exception_iterator exception_end() const {
+ if (getExceptionSpecType() != EST_Dynamic)
+ return exception_begin();
return exception_begin() + NumExceptions;
}
@@ -2535,7 +2578,7 @@ public:
void Profile(llvm::FoldingSetNodeID &ID);
static void Profile(llvm::FoldingSetNodeID &ID, QualType Result,
arg_type_iterator ArgTys, unsigned NumArgs,
- const ExtProtoInfo &EPI);
+ const ExtProtoInfo &EPI, const ASTContext *Context);
};
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index bac7050ae0..3a6c43c269 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -560,6 +560,8 @@ def err_deep_exception_specs_differ : Error<
"exception specifications of %select{return|argument}0 types differ">;
def warn_missing_exception_specification : Warning<
"%0 is missing exception specification '%1'">;
+def err_noexcept_needs_constant_expression : Error<
+ "argument to noexcept specifier must be a constant expression">;
// C++ access checking
def err_class_redeclared_with_different_access : Error<
diff --git a/include/clang/Basic/ExceptionSpecificationType.h b/include/clang/Basic/ExceptionSpecificationType.h
index 48621c73d7..aecf6eb269 100644
--- a/include/clang/Basic/ExceptionSpecificationType.h
+++ b/include/clang/Basic/ExceptionSpecificationType.h
@@ -19,14 +19,15 @@ namespace clang {
/// \brief The various types of exception specifications that exist in C++0x.
enum ExceptionSpecificationType {
EST_None, ///< no exception specification
- EST_Dynamic, ///< throw() or throw(T1, T2)
- EST_DynamicAny, ///< Microsoft throw(...) extension
+ EST_DynamicNone, ///< throw()
+ EST_Dynamic, ///< throw(T1, T2)
+ EST_MSAny, ///< Microsoft throw(...) extension
EST_BasicNoexcept, ///< noexcept
EST_ComputedNoexcept ///< noexcept(expression)
};
inline bool isDynamicExceptionSpec(ExceptionSpecificationType ESpecType) {
- return ESpecType == EST_Dynamic || ESpecType == EST_DynamicAny;
+ return ESpecType >= EST_DynamicNone && ESpecType <= EST_MSAny;
}
inline bool isNoexceptExceptionSpec(ExceptionSpecificationType ESpecType) {
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index c92bf5984d..0ba1f2e278 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -757,7 +757,8 @@ public:
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc,
bool *MissingExceptionSpecification = 0,
- bool *MissingEmptyExceptionSpecification = 0);
+ bool *MissingEmptyExceptionSpecification = 0,
+ bool AllowNoexceptAllMatchWithNoSpec = false);
bool CheckExceptionSpecSubset(
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
const FunctionProtoType *Superset, SourceLocation SuperLoc,
@@ -1076,8 +1077,9 @@ public:
bool MergeFunctionDecl(FunctionDecl *New, Decl *Old);
bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old);
void mergeObjCMethodDecls(ObjCMethodDecl *New, const ObjCMethodDecl *Old);
- void MergeVarDeclTypes(VarDecl *New, VarDecl *Old);
void MergeVarDecl(VarDecl *New, LookupResult &OldDecls);
+ void MergeVarDeclTypes(VarDecl *New, VarDecl *Old);
+ void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old);
// AssignmentAction - This is used by all the assignment diagnostic functions
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;
}
/// ParseTrailingRetur