From: Richard Smith Date: Thu, 20 Mar 2014 21:47:22 +0000 (+0000) Subject: When the exception specification for a function in an imported PCH or module is X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3ac814b3ffecb43d2b2f6d5d9d763555dd3e0f6a;p=clang When the exception specification for a function in an imported PCH or module is resolved, emit an update record. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@204403 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h index 6d12a92c61..32063d647f 100644 --- a/include/clang/AST/ASTMutationListener.h +++ b/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/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 5e27001858..d1a62dcd10 100644 --- a/include/clang/Sema/Sema.h +++ b/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/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 07ab9e372e..0b60e47052 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -1100,6 +1100,10 @@ private: }; QualType readTypeRecord(unsigned Index); + void readExceptionSpec(ModuleFile &ModuleFile, + SmallVectorImpl &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/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index 6875c7672a..68c92930e9 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/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/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 5abaab8883..1a5a4edfc5 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4659,15 +4659,6 @@ computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) { return S.ComputeInheritingCtorExceptionSpec(cast(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(); if (CanonicalFPT->getExceptionSpecType() == EST_Unevaluated) - updateExceptionSpec(*this, MD->getCanonicalDecl(), - CanonicalFPT, ExceptSpec); + UpdateExceptionSpec(MD->getCanonicalDecl(), EPI); } void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index f9a8a5db46..59fd85ef71 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/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(); } +void Sema::UpdateExceptionSpec(FunctionDecl *FD, + const FunctionProtoType::ExtProtoInfo &EPI) { + const FunctionProtoType *Proto = FD->getType()->castAs(); + + // 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/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 8cfc4149e0..029f9a2dcb 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/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(); - 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/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h index ef81e69032..b6f54a472e 100644 --- a/lib/Serialization/ASTCommon.h +++ b/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/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index f7a1921e51..61576fc8b5 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/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(Record[Idx++]); - ExceptionSpecificationType EST = - static_cast(Record[Idx++]); - EPI.ExceptionSpecType = EST; - SmallVector 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(*Loc.F, Record, Idx); - EPI.ExceptionSpecTemplate = ReadDeclAs(*Loc.F, Record, Idx); - } else if (EST == EST_Unevaluated) { - EPI.ExceptionSpecDecl = ReadDeclAs(*Loc.F, Record, Idx); - } + SmallVector 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 &Exceptions, + FunctionProtoType::ExtProtoInfo &EPI, + const RecordData &Record, unsigned &Idx) { + ExceptionSpecificationType EST = + static_cast(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(ModuleFile, Record, Idx); + EPI.ExceptionSpecTemplate = + ReadDeclAs(ModuleFile, Record, Idx); + } else if (EST == EST_Unevaluated) { + EPI.ExceptionSpecDecl = ReadDeclAs(ModuleFile, Record, Idx); + } +} + class clang::TypeLocReader : public TypeLocVisitor { ASTReader &Reader; ModuleFile &F; diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index f9a080d908..53c26e94e1 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/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(D); + auto *FPT = FD->getType()->castAs(); + auto EPI = FPT->getExtProtoInfo(); + SmallVector 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(D); Reader.Context.adjustDeducedFunctionResultType( diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index a587df4145..c9d06ad03d 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/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(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(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(D)->getType()->castAs(), + 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/test/PCH/cxx11-exception-spec.cpp b/test/PCH/cxx11-exception-spec.cpp index 446619ed1c..8c7388a767 100644 --- a/test/PCH/cxx11-exception-spec.cpp +++ b/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 f() noexcept(n % 2) { return 0; } +template int g() noexcept(n % 2); -template int f() noexcept(b) {} -decltype(f()) a; -decltype(f()) 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()), ""); -static_assert(noexcept(f()), ""); +static_assert(!noexcept(f<0>()), ""); +static_assert(noexcept(f<1>()), ""); #endif