When the exception specification for a function in an imported PCH or module is

resolved, emit an update record.

llvm-svn: 204403
This commit is contained in:
Richard Smith 2014-03-20 21:47:22 +00:00
parent 56b26a5707
commit 564417a071
12 changed files with 145 additions and 58 deletions

View File

@ -65,6 +65,10 @@ public:
virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
const FunctionDecl *D) {}
/// \brief A function's exception specification has been evaluated or
/// instantiated.
virtual void ResolvedExceptionSpec(const FunctionDecl *FD) {}
/// \brief A function's return type has been deduced.
virtual void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType);

View File

@ -1128,6 +1128,8 @@ public:
CanThrowResult canThrow(const Expr *E);
const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc,
const FunctionProtoType *FPT);
void UpdateExceptionSpec(FunctionDecl *FD,
const FunctionProtoType::ExtProtoInfo &EPI);
bool CheckSpecifiedExceptionType(QualType &T, const SourceRange &Range);
bool CheckDistantExceptionSpec(QualType T);
bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New);

View File

@ -1100,6 +1100,10 @@ private:
};
QualType readTypeRecord(unsigned Index);
void readExceptionSpec(ModuleFile &ModuleFile,
SmallVectorImpl<QualType> &ExceptionStorage,
FunctionProtoType::ExtProtoInfo &EPI,
const RecordData &Record, unsigned &Index);
RecordLocation TypeCursorForIndex(unsigned Index);
void LoadedDecl(unsigned Index, Decl *D);
Decl *ReadDeclRecord(serialization::DeclID ID);

View File

@ -758,6 +758,7 @@ public:
const VarTemplateSpecializationDecl *D) override;
void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
const FunctionDecl *D) override;
void ResolvedExceptionSpec(const FunctionDecl *FD) override;
void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override;
void CompletedImplicitDefinition(const FunctionDecl *D) override;
void StaticDataMemberInstantiated(const VarDecl *D) override;

View File

@ -4659,15 +4659,6 @@ computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) {
return S.ComputeInheritingCtorExceptionSpec(cast<CXXConstructorDecl>(MD));
}
static void
updateExceptionSpec(Sema &S, FunctionDecl *FD, const FunctionProtoType *FPT,
const Sema::ImplicitExceptionSpecification &ExceptSpec) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
ExceptSpec.getEPI(EPI);
FD->setType(S.Context.getFunctionType(FPT->getReturnType(),
FPT->getParamTypes(), EPI));
}
static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S,
CXXMethodDecl *MD) {
FunctionProtoType::ExtProtoInfo EPI;
@ -4692,8 +4683,11 @@ void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD)
ImplicitExceptionSpecification ExceptSpec =
computeImplicitExceptionSpec(*this, Loc, MD);
FunctionProtoType::ExtProtoInfo EPI;
ExceptSpec.getEPI(EPI);
// Update the type of the special member to use it.
updateExceptionSpec(*this, MD, FPT, ExceptSpec);
UpdateExceptionSpec(MD, EPI);
// A user-provided destructor can be defined outside the class. When that
// happens, be sure to update the exception specification on both
@ -4701,8 +4695,7 @@ void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD)
const FunctionProtoType *CanonicalFPT =
MD->getCanonicalDecl()->getType()->castAs<FunctionProtoType>();
if (CanonicalFPT->getExceptionSpecType() == EST_Unevaluated)
updateExceptionSpec(*this, MD->getCanonicalDecl(),
CanonicalFPT, ExceptSpec);
UpdateExceptionSpec(MD->getCanonicalDecl(), EPI);
}
void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {

View File

@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
@ -132,6 +133,25 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
return SourceDecl->getType()->castAs<FunctionProtoType>();
}
void Sema::UpdateExceptionSpec(FunctionDecl *FD,
const FunctionProtoType::ExtProtoInfo &EPI) {
const FunctionProtoType *Proto = FD->getType()->castAs<FunctionProtoType>();
// Overwrite the exception spec and rebuild the function type.
FunctionProtoType::ExtProtoInfo NewEPI = Proto->getExtProtoInfo();
NewEPI.ExceptionSpecType = EPI.ExceptionSpecType;
NewEPI.NumExceptions = EPI.NumExceptions;
NewEPI.Exceptions = EPI.Exceptions;
NewEPI.NoexceptExpr = EPI.NoexceptExpr;
FD->setType(Context.getFunctionType(Proto->getReturnType(),
Proto->getParamTypes(), NewEPI));
// If we've fully resolved the exception specification, notify listeners.
if (!isUnresolvedExceptionSpec(EPI.ExceptionSpecType))
if (auto *Listener = getASTMutationListener())
Listener->ResolvedExceptionSpec(FD);
}
/// Determine whether a function has an implicitly-generated exception
/// specification.
static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {

View File

@ -3131,19 +3131,13 @@ static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
}
}
// Rebuild the function type
const FunctionProtoType *NewProto
= New->getType()->getAs<FunctionProtoType>();
assert(NewProto && "Template instantiation without function prototype?");
FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = Proto->getExceptionSpecType();
EPI.NumExceptions = Exceptions.size();
EPI.Exceptions = Exceptions.data();
EPI.NoexceptExpr = NoexceptExpr;
New->setType(SemaRef.Context.getFunctionType(NewProto->getReturnType(),
NewProto->getParamTypes(), EPI));
SemaRef.UpdateExceptionSpec(New, EPI);
}
void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
@ -3157,10 +3151,9 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
if (Inst.isInvalid()) {
// We hit the instantiation depth limit. Clear the exception specification
// so that our callers don't have to cope with EST_Uninstantiated.
FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_None;
Decl->setType(Context.getFunctionType(Proto->getReturnType(),
Proto->getParamTypes(), EPI));
UpdateExceptionSpec(Decl, EPI);
return;
}

View File

@ -26,6 +26,7 @@ enum DeclUpdateKind {
UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
UPD_CXX_ADDED_ANONYMOUS_NAMESPACE,
UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER,
UPD_CXX_RESOLVED_EXCEPTION_SPEC,
UPD_CXX_DEDUCED_RETURN_TYPE,
UPD_DECL_MARKED_USED
};

View File

@ -5036,23 +5036,8 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
EPI.HasTrailingReturn = Record[Idx++];
EPI.TypeQuals = Record[Idx++];
EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]);
ExceptionSpecificationType EST =
static_cast<ExceptionSpecificationType>(Record[Idx++]);
EPI.ExceptionSpecType = EST;
SmallVector<QualType, 2> Exceptions;
if (EST == EST_Dynamic) {
EPI.NumExceptions = Record[Idx++];
for (unsigned I = 0; I != EPI.NumExceptions; ++I)
Exceptions.push_back(readType(*Loc.F, Record, Idx));
EPI.Exceptions = Exceptions.data();
} else if (EST == EST_ComputedNoexcept) {
EPI.NoexceptExpr = ReadExpr(*Loc.F);
} else if (EST == EST_Uninstantiated) {
EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
EPI.ExceptionSpecTemplate = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
} else if (EST == EST_Unevaluated) {
EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
}
SmallVector<QualType, 8> ExceptionStorage;
readExceptionSpec(*Loc.F, ExceptionStorage, EPI, Record, Idx);
return Context.getFunctionType(ResultType, ParamTypes, EPI);
}
@ -5307,6 +5292,29 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
llvm_unreachable("Invalid TypeCode!");
}
void ASTReader::readExceptionSpec(ModuleFile &ModuleFile,
SmallVectorImpl<QualType> &Exceptions,
FunctionProtoType::ExtProtoInfo &EPI,
const RecordData &Record, unsigned &Idx) {
ExceptionSpecificationType EST =
static_cast<ExceptionSpecificationType>(Record[Idx++]);
EPI.ExceptionSpecType = EST;
if (EST == EST_Dynamic) {
EPI.NumExceptions = Record[Idx++];
for (unsigned I = 0; I != EPI.NumExceptions; ++I)
Exceptions.push_back(readType(ModuleFile, Record, Idx));
EPI.Exceptions = Exceptions.data();
} else if (EST == EST_ComputedNoexcept) {
EPI.NoexceptExpr = ReadExpr(ModuleFile);
} else if (EST == EST_Uninstantiated) {
EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
EPI.ExceptionSpecTemplate =
ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
} else if (EST == EST_Unevaluated) {
EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
}
}
class clang::TypeLocReader : public TypeLocVisitor<TypeLocReader> {
ASTReader &Reader;
ModuleFile &F;

View File

@ -2944,6 +2944,17 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
Reader.ReadSourceLocation(ModuleFile, Record, Idx));
break;
case UPD_CXX_RESOLVED_EXCEPTION_SPEC: {
auto *FD = cast<FunctionDecl>(D);
auto *FPT = FD->getType()->castAs<FunctionProtoType>();
auto EPI = FPT->getExtProtoInfo();
SmallVector<QualType, 8> ExceptionStorage;
Reader.readExceptionSpec(ModuleFile, ExceptionStorage, EPI, Record, Idx);
FD->setType(Reader.Context.getFunctionType(FPT->getReturnType(),
FPT->getParamTypes(), EPI));
break;
}
case UPD_CXX_DEDUCED_RETURN_TYPE: {
FunctionDecl *FD = cast<FunctionDecl>(D);
Reader.Context.adjustDeducedFunctionResultType(

View File

@ -194,15 +194,8 @@ void ASTTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
Code = TYPE_FUNCTION_NO_PROTO;
}
void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
VisitFunctionType(T);
Record.push_back(T->getNumParams());
for (unsigned I = 0, N = T->getNumParams(); I != N; ++I)
Writer.AddTypeRef(T->getParamType(I), Record);
Record.push_back(T->isVariadic());
Record.push_back(T->hasTrailingReturn());
Record.push_back(T->getTypeQuals());
Record.push_back(static_cast<unsigned>(T->getRefQualifier()));
static void addExceptionSpec(ASTWriter &Writer, const FunctionProtoType *T,
ASTWriter::RecordDataImpl &Record) {
Record.push_back(T->getExceptionSpecType());
if (T->getExceptionSpecType() == EST_Dynamic) {
Record.push_back(T->getNumExceptions());
@ -216,6 +209,18 @@ void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
} else if (T->getExceptionSpecType() == EST_Unevaluated) {
Writer.AddDeclRef(T->getExceptionSpecDecl(), Record);
}
}
void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
VisitFunctionType(T);
Record.push_back(T->getNumParams());
for (unsigned I = 0, N = T->getNumParams(); I != N; ++I)
Writer.AddTypeRef(T->getParamType(I), Record);
Record.push_back(T->isVariadic());
Record.push_back(T->hasTrailingReturn());
Record.push_back(T->getTypeQuals());
Record.push_back(static_cast<unsigned>(T->getRefQualifier()));
addExceptionSpec(Writer, T, Record);
Code = TYPE_FUNCTION_PROTO;
}
@ -4341,6 +4346,13 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
AddSourceLocation(Update.getLoc(), Record);
break;
case UPD_CXX_RESOLVED_EXCEPTION_SPEC:
addExceptionSpec(
*this,
cast<FunctionDecl>(D)->getType()->castAs<FunctionProtoType>(),
Record);
break;
case UPD_CXX_DEDUCED_RETURN_TYPE:
Record.push_back(GetOrCreateTypeID(Update.getType()));
break;
@ -5305,6 +5317,15 @@ void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
DeclUpdates[TD].push_back({UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, D});
}
void ASTWriter::ResolvedExceptionSpec(const FunctionDecl *FD) {
assert(!WritingAST && "Already writing the AST!");
FD = FD->getCanonicalDecl();
if (!FD->isFromASTFile())
return; // Not a function declared in PCH and defined outside.
DeclUpdates[FD].push_back(UPD_CXX_RESOLVED_EXCEPTION_SPEC);
}
void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) {
assert(!WritingAST && "Already writing the AST!");
FD = FD->getCanonicalDecl();

View File

@ -1,18 +1,47 @@
// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t
// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s
// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t.1
// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t.1 -emit-pch %s -o %t.2
// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t.2 -verify %s
// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t.2 -emit-llvm-only %s
// expected-no-diagnostics
#ifndef HEADER_INCLUDED
#ifndef PHASE1_DONE
#define PHASE1_DONE
#define HEADER_INCLUDED
template<int n> int f() noexcept(n % 2) { return 0; }
template<int n> int g() noexcept(n % 2);
template<bool b> int f() noexcept(b) {}
decltype(f<false>()) a;
decltype(f<true>()) b;
decltype(f<2>()) f0;
decltype(f<3>()) f1;
template int f<4>();
template int f<5>();
decltype(f<6>()) f6;
decltype(f<7>()) f7;
struct A {
A();
A(const A&);
};
decltype(g<0>()) g0;
#elif !defined(PHASE2_DONE)
#define PHASE2_DONE
template int f<6>();
template int f<7>();
decltype(f<8>()) f8;
decltype(f<9>()) f9;
template int f<10>();
template int f<11>();
A::A() = default;
A::A(const A&) = default;
int g0val = g<0>();
#else
static_assert(!noexcept(f<false>()), "");
static_assert(noexcept(f<true>()), "");
static_assert(!noexcept(f<0>()), "");
static_assert(noexcept(f<1>()), "");
#endif