aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;
}
/// 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()) {
//