diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/AST/ASTMutationListener.h | 4 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 2 | ||||
-rw-r--r-- | clang/include/clang/Serialization/ASTReader.h | 4 | ||||
-rw-r--r-- | clang/include/clang/Serialization/ASTWriter.h | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 17 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExceptionSpec.cpp | 20 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 15 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTCommon.h | 1 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 42 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 11 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 39 | ||||
-rw-r--r-- | clang/test/PCH/cxx11-exception-spec.cpp | 47 |
12 files changed, 145 insertions, 58 deletions
diff --git a/clang/include/clang/AST/ASTMutationListener.h b/clang/include/clang/AST/ASTMutationListener.h index 6d12a92c61b..32063d647fb 100644 --- a/clang/include/clang/AST/ASTMutationListener.h +++ b/clang/include/clang/AST/ASTMutationListener.h @@ -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); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 5e27001858f..d1a62dcd100 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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); diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 07ab9e372e4..0b60e470521 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -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); diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index 6875c7672a4..68c92930e9b 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -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; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 5abaab8883a..1a5a4edfc50 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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) { diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index f9a8a5db466..59fd85ef710 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -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) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 8cfc4149e06..029f9a2dcbf 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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; } diff --git a/clang/lib/Serialization/ASTCommon.h b/clang/lib/Serialization/ASTCommon.h index ef81e690324..b6f54a472ee 100644 --- a/clang/lib/Serialization/ASTCommon.h +++ b/clang/lib/Serialization/ASTCommon.h @@ -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 }; diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index f7a1921e519..61576fc8b57 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -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; diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index f9a080d9088..53c26e94e1f 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -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( diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index a587df41458..c9d06ad03d9 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -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(); diff --git a/clang/test/PCH/cxx11-exception-spec.cpp b/clang/test/PCH/cxx11-exception-spec.cpp index 446619ed1c9..8c7388a767b 100644 --- a/clang/test/PCH/cxx11-exception-spec.cpp +++ b/clang/test/PCH/cxx11-exception-spec.cpp @@ -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 |