diff options
author | dim <dim@FreeBSD.org> | 2012-05-03 16:53:59 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2012-05-03 16:53:59 +0000 |
commit | 822bde9df508e0b9afac5e581b0d6ab403417a28 (patch) | |
tree | 2e51705e103e92c7be1b21e8bd8ffd5b5d0e4d52 /lib/Sema | |
parent | 50b73317314e889cf39c7b1d6cbf419fa7502f22 (diff) | |
download | FreeBSD-src-822bde9df508e0b9afac5e581b0d6ab403417a28.zip FreeBSD-src-822bde9df508e0b9afac5e581b0d6ab403417a28.tar.gz |
Vendor import of clang release_31 branch r155985:
http://llvm.org/svn/llvm-project/cfe/branches/release_31@155985
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Sema/DeclSpec.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaAccess.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 26 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 341 | ||||
-rw-r--r-- | lib/Sema/SemaExceptionSpec.cpp | 359 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 33 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 73 | ||||
-rw-r--r-- | lib/Sema/SemaExprMember.cpp | 17 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 45 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaPseudoObject.cpp | 28 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 11 | ||||
-rw-r--r-- | lib/Sema/SemaStmtAttr.cpp | 48 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 49 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 101 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 363 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 51 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 66 |
21 files changed, 1305 insertions, 326 deletions
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 5d297f9..07734c7 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -40,6 +40,7 @@ add_clang_library(clangSema SemaOverload.cpp SemaPseudoObject.cpp SemaStmt.cpp + SemaStmtAttr.cpp SemaTemplate.cpp SemaTemplateDeduction.cpp SemaTemplateInstantiate.cpp diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index b531acc..fe63e35 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -162,6 +162,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, SourceRange *ExceptionRanges, unsigned NumExceptions, Expr *NoexceptExpr, + CachedTokens *ExceptionSpecTokens, SourceLocation LocalRangeBegin, SourceLocation LocalRangeEnd, Declarator &TheDeclarator, @@ -226,6 +227,10 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, case EST_ComputedNoexcept: I.Fun.NoexceptExpr = NoexceptExpr; break; + + case EST_Delayed: + I.Fun.ExceptionSpecTokens = ExceptionSpecTokens; + break; } return I; } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index fcdfcac..30a9cd7 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -103,6 +103,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, AnalysisWarnings(*this) { TUScope = 0; + LoadedExternalKnownNamespaces = false; for (unsigned I = 0; I != NSAPI::NumNSNumberLiteralMethods; ++I) NSNumberLiteralMethods[I] = 0; diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index dea5e76..01c141e 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -779,6 +779,13 @@ static AccessResult HasAccess(Sema &S, // that the naming class has to be derived from the effective // context. + // Emulate a MSVC bug where the creation of pointer-to-member + // to protected member of base class is allowed but only from + // a static function member functions. + if (S.getLangOpts().MicrosoftMode && !EC.Functions.empty()) + if (CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(EC.Functions.front())) + if (MD->isStatic()) return AR_accessible; + // Despite the standard's confident wording, there is a case // where you can have an instance member that's neither in a // pointer-to-member expression nor in a member access: when diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 8b314b5..1550993 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4471,6 +4471,11 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier, return false; } +static bool hasDelayedExceptionSpec(CXXMethodDecl *Method) { + const FunctionProtoType *Proto =Method->getType()->getAs<FunctionProtoType>(); + return Proto && Proto->getExceptionSpecType() == EST_Delayed; +} + /// AddOverriddenMethods - See if a method overrides any in the base classes, /// and if so, check that it's a valid override and remember it. bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { @@ -4486,7 +4491,8 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) { MD->addOverriddenMethod(OldMD->getCanonicalDecl()); if (!CheckOverridingFunctionReturnType(MD, OldMD) && - !CheckOverridingFunctionExceptionSpec(MD, OldMD) && + (hasDelayedExceptionSpec(MD) || + !CheckOverridingFunctionExceptionSpec(MD, OldMD)) && !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) { AddedAny = true; } @@ -5834,6 +5840,9 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, } } } + + if (Method->isStatic()) + checkThisInStaticMemberFunctionType(Method); } // Extra checking for C++ overloaded operators (C++ [over.oper]). @@ -7176,8 +7185,7 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, } } -Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, - Declarator &D) { +Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { assert(getCurFunctionDecl() == 0 && "Function parsing confused"); assert(D.isFunctionDeclarator() && "Not a function declarator!"); Scope *ParentScope = FnBodyScope->getParent(); @@ -7350,6 +7358,10 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { } } + // Ensure that the function's exception specification is instantiated. + if (const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>()) + ResolveExceptionSpec(D->getLocation(), FPT); + // Checking attributes of current function definition // dllimport attribute. DLLImportAttr *DA = FD->getAttr<DLLImportAttr>(); @@ -7554,7 +7566,11 @@ void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D, // Always attach attributes to the underlying decl. if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) D = TD->getTemplatedDecl(); - ProcessDeclAttributeList(S, D, Attrs.getList()); + ProcessDeclAttributeList(S, D, Attrs.getList()); + + if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(D)) + if (Method->isStatic()) + checkThisInStaticMemberFunctionAttributes(Method); } @@ -7619,7 +7635,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, SourceLocation(), SourceLocation(), SourceLocation(), EST_None, SourceLocation(), - 0, 0, 0, 0, Loc, Loc, D), + 0, 0, 0, 0, 0, Loc, Loc, D), DS.getAttributes(), SourceLocation()); D.SetIdentifier(&II, Loc); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 847f03c..1d251b9 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -25,6 +25,7 @@ #include "clang/AST/DeclVisitor.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/RecordLayout.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" @@ -124,14 +125,17 @@ namespace { } } -void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) { - assert(Context && "ImplicitExceptionSpecification without an ASTContext"); +void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, + CXXMethodDecl *Method) { // If we have an MSAny or unknown spec already, don't bother. if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed) return; const FunctionProtoType *Proto = Method->getType()->getAs<FunctionProtoType>(); + Proto = Self->ResolveExceptionSpec(CallLoc, Proto); + if (!Proto) + return; ExceptionSpecificationType EST = Proto->getExceptionSpecType(); @@ -163,7 +167,8 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) { // Check out noexcept specs. if (EST == EST_ComputedNoexcept) { - FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec(*Context); + FunctionProtoType::NoexceptResult NR = + Proto->getNoexceptSpec(Self->Context); assert(NR != FunctionProtoType::NR_NoNoexcept && "Must have noexcept result for EST_ComputedNoexcept."); assert(NR != FunctionProtoType::NR_Dependent && @@ -187,7 +192,7 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) { for (FunctionProtoType::exception_iterator E = Proto->exception_begin(), EEnd = Proto->exception_end(); E != EEnd; ++E) - if (ExceptionsSeen.insert(Context->getCanonicalType(*E))) + if (ExceptionsSeen.insert(Self->Context.getCanonicalType(*E))) Exceptions.push_back(*E); } @@ -216,7 +221,7 @@ void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) { // implicit definition. For now, we assume that any non-nothrow expression can // throw any exception. - if (E->CanThrow(*Context)) + if (Self->canThrow(E)) ComputedEST = EST_None; } @@ -3921,7 +3926,7 @@ void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) { HadError = true; } - ImplicitExceptionSpecification Spec(Context); + ImplicitExceptionSpecification Spec(*this); bool Const; llvm::tie(Spec, Const) = ComputeDefaultedCopyCtorExceptionSpecAndConst(CD->getParent()); @@ -4030,7 +4035,7 @@ void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) { HadError = true; } - ImplicitExceptionSpecification Spec(Context); + ImplicitExceptionSpecification Spec(*this); bool Const; llvm::tie(Spec, Const) = ComputeDefaultedCopyCtorExceptionSpecAndConst(MD->getParent()); @@ -5920,10 +5925,12 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, case UnqualifiedId::IK_ConstructorName: case UnqualifiedId::IK_ConstructorTemplateId: - // C++0x inherited constructors. + // C++11 inheriting constructors. Diag(Name.getLocStart(), getLangOpts().CPlusPlus0x ? - diag::warn_cxx98_compat_using_decl_constructor : + // FIXME: Produce warn_cxx98_compat_using_decl_constructor + // instead once inheriting constructors work. + diag::err_using_decl_constructor_unsupported : diag::err_using_decl_constructor) << SS.getRange(); @@ -6813,7 +6820,7 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] - ImplicitExceptionSpecification ExceptSpec(Context); + ImplicitExceptionSpecification ExceptSpec(*this); if (ClassDecl->isInvalidDecl()) return ExceptSpec; @@ -6830,7 +6837,7 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. if (Constructor) - ExceptSpec.CalledDecl(Constructor); + ExceptSpec.CalledDecl(B->getLocStart(), Constructor); } } @@ -6844,7 +6851,7 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. if (Constructor) - ExceptSpec.CalledDecl(Constructor); + ExceptSpec.CalledDecl(B->getLocStart(), Constructor); } } @@ -6867,7 +6874,7 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // might just be ill-formed because this function attempts to refer to // a deleted function here. if (Constructor) - ExceptSpec.CalledDecl(Constructor); + ExceptSpec.CalledDecl(F->getLocation(), Constructor); } } @@ -6989,6 +6996,7 @@ void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) { const FunctionProtoType *CtorTy = CtorDecl->getType()->castAs<FunctionProtoType>(); if (CtorTy->getExceptionSpecType() == EST_Delayed) { + // FIXME: Don't do this unless the exception spec is needed. ImplicitExceptionSpecification Spec = ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl); FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); @@ -7189,7 +7197,7 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) { // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have // an exception-specification. - ImplicitExceptionSpecification ExceptSpec(Context); + ImplicitExceptionSpecification ExceptSpec(*this); if (ClassDecl->isInvalidDecl()) return ExceptSpec; @@ -7201,7 +7209,7 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) { continue; if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) - ExceptSpec.CalledDecl( + ExceptSpec.CalledDecl(B->getLocStart(), LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl()))); } @@ -7210,7 +7218,7 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) { BEnd = ClassDecl->vbases_end(); B != BEnd; ++B) { if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) - ExceptSpec.CalledDecl( + ExceptSpec.CalledDecl(B->getLocStart(), LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl()))); } @@ -7220,7 +7228,7 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) { F != FEnd; ++F) { if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs<RecordType>()) - ExceptSpec.CalledDecl( + ExceptSpec.CalledDecl(F->getLocation(), LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl()))); } @@ -7545,7 +7553,7 @@ std::pair<Sema::ImplicitExceptionSpecification, bool> Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( CXXRecordDecl *ClassDecl) { if (ClassDecl->isInvalidDecl()) - return std::make_pair(ImplicitExceptionSpecification(Context), false); + return std::make_pair(ImplicitExceptionSpecification(*this), false); // C++ [class.copy]p10: // If the class definition does not explicitly declare a copy @@ -7618,7 +7626,7 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( // Based on a similar decision made for constness in C++0x, we're erring on // the side of assuming such calls to be made regardless of whether they // actually happen. - ImplicitExceptionSpecification ExceptSpec(Context); + ImplicitExceptionSpecification ExceptSpec(*this); unsigned ArgQuals = HasConstCopyAssignment ? Qualifiers::Const : 0; for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); @@ -7630,7 +7638,7 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl, ArgQuals, false, 0)) - ExceptSpec.CalledDecl(CopyAssign); + ExceptSpec.CalledDecl(Base->getLocStart(), CopyAssign); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), @@ -7640,7 +7648,7 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl, ArgQuals, false, 0)) - ExceptSpec.CalledDecl(CopyAssign); + ExceptSpec.CalledDecl(Base->getLocStart(), CopyAssign); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), @@ -7651,7 +7659,7 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(FieldClassDecl, ArgQuals, false, 0)) - ExceptSpec.CalledDecl(CopyAssign); + ExceptSpec.CalledDecl(Field->getLocation(), CopyAssign); } } @@ -7664,7 +7672,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { // for determining the argument type of the operator. Note also that // operators taking an object instead of a reference are allowed. - ImplicitExceptionSpecification Spec(Context); + ImplicitExceptionSpecification Spec(*this); bool Const; llvm::tie(Spec, Const) = ComputeDefaultedCopyAssignmentExceptionSpecAndConst(ClassDecl); @@ -8031,7 +8039,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, Sema::ImplicitExceptionSpecification Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { - ImplicitExceptionSpecification ExceptSpec(Context); + ImplicitExceptionSpecification ExceptSpec(*this); if (ClassDecl->isInvalidDecl()) return ExceptSpec; @@ -8058,7 +8066,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, false, 0)) - ExceptSpec.CalledDecl(MoveAssign); + ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), @@ -8068,7 +8076,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, false, 0)) - ExceptSpec.CalledDecl(MoveAssign); + ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), @@ -8079,7 +8087,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(FieldClassDecl, false, 0)) - ExceptSpec.CalledDecl(MoveAssign); + ExceptSpec.CalledDecl(Field->getLocation(), MoveAssign); } } @@ -8577,7 +8585,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, std::pair<Sema::ImplicitExceptionSpecification, bool> Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { if (ClassDecl->isInvalidDecl()) - return std::make_pair(ImplicitExceptionSpecification(Context), false); + return std::make_pair(ImplicitExceptionSpecification(*this), false); // C++ [class.copy]p5: // The implicitly-declared copy constructor for a class X will @@ -8638,7 +8646,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] - ImplicitExceptionSpecification ExceptSpec(Context); + ImplicitExceptionSpecification ExceptSpec(*this); unsigned Quals = HasConstCopyConstructor? Qualifiers::Const : 0; for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); @@ -8652,7 +8660,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (CXXConstructorDecl *CopyConstructor = LookupCopyingConstructor(BaseClassDecl, Quals)) - ExceptSpec.CalledDecl(CopyConstructor); + ExceptSpec.CalledDecl(Base->getLocStart(), CopyConstructor); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), BaseEnd = ClassDecl->vbases_end(); @@ -8662,7 +8670,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (CXXConstructorDecl *CopyConstructor = LookupCopyingConstructor(BaseClassDecl, Quals)) - ExceptSpec.CalledDecl(CopyConstructor); + ExceptSpec.CalledDecl(Base->getLocStart(), CopyConstructor); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); @@ -8672,7 +8680,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { if (CXXConstructorDecl *CopyConstructor = LookupCopyingConstructor(FieldClassDecl, Quals)) - ExceptSpec.CalledDecl(CopyConstructor); + ExceptSpec.CalledDecl(Field->getLocation(), CopyConstructor); } } @@ -8685,7 +8693,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // If the class definition does not explicitly declare a copy // constructor, one is declared implicitly. - ImplicitExceptionSpecification Spec(Context); + ImplicitExceptionSpecification Spec(*this); bool Const; llvm::tie(Spec, Const) = ComputeDefaultedCopyCtorExceptionSpecAndConst(ClassDecl); @@ -8783,7 +8791,7 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] - ImplicitExceptionSpecification ExceptSpec(Context); + ImplicitExceptionSpecification ExceptSpec(*this); if (ClassDecl->isInvalidDecl()) return ExceptSpec; @@ -8800,7 +8808,7 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. if (Constructor) - ExceptSpec.CalledDecl(Constructor); + ExceptSpec.CalledDecl(B->getLocStart(), Constructor); } } @@ -8814,7 +8822,7 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. if (Constructor) - ExceptSpec.CalledDecl(Constructor); + ExceptSpec.CalledDecl(B->getLocStart(), Constructor); } } @@ -8832,7 +8840,7 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // might just be ill-formed because this function attempts to refer to // a deleted function here. if (Constructor) - ExceptSpec.CalledDecl(Constructor); + ExceptSpec.CalledDecl(F->getLocation(), Constructor); } } @@ -11053,6 +11061,265 @@ void Sema::CheckDelegatingCtorCycles() { (*CI)->setInvalidDecl(); } +namespace { + /// \brief AST visitor that finds references to the 'this' expression. + class FindCXXThisExpr : public RecursiveASTVisitor<FindCXXThisExpr> { + Sema &S; + + public: + explicit FindCXXThisExpr(Sema &S) : S(S) { } + + bool VisitCXXThisExpr(CXXThisExpr *E) { + S.Diag(E->getLocation(), diag::err_this_static_member_func) + << E->isImplicit(); + return false; + } + }; +} + +bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) { + TypeSourceInfo *TSInfo = Method->getTypeSourceInfo(); + if (!TSInfo) + return false; + + TypeLoc TL = TSInfo->getTypeLoc(); + FunctionProtoTypeLoc *ProtoTL = dyn_cast<FunctionProtoTypeLoc>(&TL); + if (!ProtoTL) + return false; + + // C++11 [expr.prim.general]p3: + // [The expression this] shall not appear before the optional + // cv-qualifier-seq and it shall not appear within the declaration of a + // static member function (although its type and value category are defined + // within a static member function as they are within a non-static member + // function). [ Note: this is because declaration matching does not occur + // until the complete declarator is known. - end note ] + const FunctionProtoType *Proto = ProtoTL->getTypePtr(); + FindCXXThisExpr Finder(*this); + + // If the return type came after the cv-qualifier-seq, check it now. + if (Proto->hasTrailingReturn() && + !Finder.TraverseTypeLoc(ProtoTL->getResultLoc())) + return true; + + // Check the exception specification. + if (checkThisInStaticMemberFunctionExceptionSpec(Method)) + return true; + + return checkThisInStaticMemberFunctionAttributes(Method); +} + +bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) { + TypeSourceInfo *TSInfo = Method->getTypeSourceInfo(); + if (!TSInfo) + return false; + + TypeLoc TL = TSInfo->getTypeLoc(); + FunctionProtoTypeLoc *ProtoTL = dyn_cast<FunctionProtoTypeLoc>(&TL); + if (!ProtoTL) + return false; + + const FunctionProtoType *Proto = ProtoTL->getTypePtr(); + FindCXXThisExpr Finder(*this); + + switch (Proto->getExceptionSpecType()) { + case EST_Uninstantiated: + case EST_BasicNoexcept: + case EST_Delayed: + case EST_DynamicNone: + case EST_MSAny: + case EST_None: + break; + + case EST_ComputedNoexcept: + if (!Finder.TraverseStmt(Proto->getNoexceptExpr())) + return true; + + case EST_Dynamic: + for (FunctionProtoType::exception_iterator E = Proto->exception_begin(), + EEnd = Proto->exception_end(); + E != EEnd; ++E) { + if (!Finder.TraverseType(*E)) + return true; + } + break; + } + + return false; +} + +bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) { + FindCXXThisExpr Finder(*this); + + // Check attributes. + for (Decl::attr_iterator A = Method->attr_begin(), AEnd = Method->attr_end(); + A != AEnd; ++A) { + // FIXME: This should be emitted by tblgen. + Expr *Arg = 0; + ArrayRef<Expr *> Args; + if (GuardedByAttr *G = dyn_cast<GuardedByAttr>(*A)) + Arg = G->getArg(); + else if (PtGuardedByAttr *G = dyn_cast<PtGuardedByAttr>(*A)) + Arg = G->getArg(); + else if (AcquiredAfterAttr *AA = dyn_cast<AcquiredAfterAttr>(*A)) + Args = ArrayRef<Expr *>(AA->args_begin(), AA->args_size()); + else if (AcquiredBeforeAttr *AB = dyn_cast<AcquiredBeforeAttr>(*A)) + Args = ArrayRef<Expr *>(AB->args_begin(), AB->args_size()); + else if (ExclusiveLockFunctionAttr *ELF + = dyn_cast<ExclusiveLockFunctionAttr>(*A)) + Args = ArrayRef<Expr *>(ELF->args_begin(), ELF->args_size()); + else if (SharedLockFunctionAttr *SLF + = dyn_cast<SharedLockFunctionAttr>(*A)) + Args = ArrayRef<Expr *>(SLF->args_begin(), SLF->args_size()); + else if (ExclusiveTrylockFunctionAttr *ETLF + = dyn_cast<ExclusiveTrylockFunctionAttr>(*A)) { + Arg = ETLF->getSuccessValue(); + Args = ArrayRef<Expr *>(ETLF->args_begin(), ETLF->args_size()); + } else if (SharedTrylockFunctionAttr *STLF + = dyn_cast<SharedTrylockFunctionAttr>(*A)) { + Arg = STLF->getSuccessValue(); + Args = ArrayRef<Expr *>(STLF->args_begin(), STLF->args_size()); + } else if (UnlockFunctionAttr *UF = dyn_cast<UnlockFunctionAttr>(*A)) + Args = ArrayRef<Expr *>(UF->args_begin(), UF->args_size()); + else if (LockReturnedAttr *LR = dyn_cast<LockReturnedAttr>(*A)) + Arg = LR->getArg(); + else if (LocksExcludedAttr *LE = dyn_cast<LocksExcludedAttr>(*A)) + Args = ArrayRef<Expr *>(LE->args_begin(), LE->args_size()); + else if (ExclusiveLocksRequiredAttr *ELR + = dyn_cast<ExclusiveLocksRequiredAttr>(*A)) + Args = ArrayRef<Expr *>(ELR->args_begin(), ELR->args_size()); + else if (SharedLocksRequiredAttr *SLR + = dyn_cast<SharedLocksRequiredAttr>(*A)) + Args = ArrayRef<Expr *>(SLR->args_begin(), SLR->args_size()); + + if (Arg && !Finder.TraverseStmt(Arg)) + return true; + + for (unsigned I = 0, N = Args.size(); I != N; ++I) { + if (!Finder.TraverseStmt(Args[I])) + return true; + } + } + + return false; +} + +void +Sema::checkExceptionSpecification(ExceptionSpecificationType EST, + ArrayRef<ParsedType> DynamicExceptions, + ArrayRef<SourceRange> DynamicExceptionRanges, + Expr *NoexceptExpr, + llvm::SmallVectorImpl<QualType> &Exceptions, + FunctionProtoType::ExtProtoInfo &EPI) { + Exceptions.clear(); + EPI.ExceptionSpecType = EST; + if (EST == EST_Dynamic) { + Exceptions.reserve(DynamicExceptions.size()); + for (unsigned ei = 0, ee = DynamicExceptions.size(); ei != ee; ++ei) { + // FIXME: Preserve type source info. + QualType ET = GetTypeFromParser(DynamicExceptions[ei]); + + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + collectUnexpandedParameterPacks(ET, Unexpanded); + if (!Unexpanded.empty()) { + DiagnoseUnexpandedParameterPacks(DynamicExceptionRanges[ei].getBegin(), + UPPC_ExceptionType, + Unexpanded); + continue; + } + + // Check that the type is valid for an exception spec, and + // drop it if not. + if (!CheckSpecifiedExceptionType(ET, DynamicExceptionRanges[ei])) + Exceptions.push_back(ET); + } + EPI.NumExceptions = Exceptions.size(); + EPI.Exceptions = Exceptions.data(); + return; + } + + if (EST == EST_ComputedNoexcept) { + // If an error occurred, there's no expression here. + if (NoexceptExpr) { + assert((NoexceptExpr->isTypeDependent() || + NoexceptExpr->getType()->getCanonicalTypeUnqualified() == + Context.BoolTy) && + "Parser should have made sure that the expression is boolean"); + if (NoexceptExpr && DiagnoseUnexpandedParameterPack(NoexceptExpr)) { + EPI.ExceptionSpecType = EST_BasicNoexcept; + return; + } + + if (!NoexceptExpr->isValueDependent()) + NoexceptExpr = VerifyIntegerConstantExpression(NoexceptExpr, 0, + PDiag(diag::err_noexcept_needs_constant_expression), + /*AllowFold*/ false).take(); + EPI.NoexceptExpr = NoexceptExpr; + } + return; + } +} + +void Sema::actOnDelayedExceptionSpecification(Decl *MethodD, + ExceptionSpecificationType EST, + SourceRange SpecificationRange, + ArrayRef<ParsedType> DynamicExceptions, + ArrayRef<SourceRange> DynamicExceptionRanges, + Expr *NoexceptExpr) { + if (!MethodD) + return; + + // Dig out the method we're referring to. + CXXMethodDecl *Method = 0; + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(MethodD)) + Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl()); + else + Method = dyn_cast<CXXMethodDecl>(MethodD); + + if (!Method) + return; + + // Dig out the prototype. This should never fail. + const FunctionProtoType *Proto + = dyn_cast<FunctionProtoType>(Method->getType()); + if (!Proto) + return; + + // Check the exception specification. + llvm::SmallVector<QualType, 4> Exceptions; + FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); + checkExceptionSpecification(EST, DynamicExceptions, DynamicExceptionRanges, + NoexceptExpr, Exceptions, EPI); + + // Rebuild the function type. + QualType T = Context.getFunctionType(Proto->getResultType(), + Proto->arg_type_begin(), + Proto->getNumArgs(), + EPI); + if (TypeSourceInfo *TSInfo = Method->getTypeSourceInfo()) { + // FIXME: When we get proper type location information for exceptions, + // we'll also have to rebuild the TypeSourceInfo. For now, we just patch + // up the TypeSourceInfo; + assert(TypeLoc::getFullDataSizeForType(T) + == TypeLoc::getFullDataSizeForType(Method->getType()) && + "TypeLoc size mismatch with delayed exception specification"); + TSInfo->overrideType(T); + } + + Method->setType(T); + + if (Method->isStatic()) + checkThisInStaticMemberFunctionExceptionSpec(Method); + + if (Method->isVirtual()) { + // Check overrides, which we previously had to delay. + for (CXXMethodDecl::method_iterator O = Method->begin_overridden_methods(), + OEnd = Method->end_overridden_methods(); + O != OEnd; ++O) + CheckOverridingFunctionExceptionSpec(Method, *O); + } +} + /// IdentifyCUDATarget - Determine the CUDA compilation target for this function Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) { // Implicitly declared functions (e.g. copy constructors) are diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 42221f8..14b2434 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -96,6 +96,26 @@ bool Sema::CheckDistantExceptionSpec(QualType T) { return FnT->hasExceptionSpec(); } +const FunctionProtoType * +Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { + // FIXME: If FD is a special member, we should delay computing its exception + // specification until this point. + if (FPT->getExceptionSpecType() != EST_Uninstantiated) + return FPT; + + FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl(); + const FunctionProtoType *SourceFPT = + SourceDecl->getType()->castAs<FunctionProtoType>(); + + if (SourceFPT->getExceptionSpecType() != EST_Uninstantiated) + return SourceFPT; + + // Instantiate the exception specification now. + InstantiateExceptionSpec(Loc, SourceDecl); + + return SourceDecl->getType()->castAs<FunctionProtoType>(); +} + bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator(); bool IsOperatorNew = OO == OO_New || OO == OO_Array_New; @@ -104,7 +124,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { unsigned DiagID = diag::err_mismatched_exception_spec; if (getLangOpts().MicrosoftExt) DiagID = diag::warn_mismatched_exception_spec; - + if (!CheckEquivalentExceptionSpec(PDiag(DiagID), PDiag(diag::note_previous_declaration), Old->getType()->getAs<FunctionProtoType>(), @@ -295,6 +315,13 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, if (MissingEmptyExceptionSpecification) *MissingEmptyExceptionSpecification = false; + Old = ResolveExceptionSpec(NewLoc, Old); + if (!Old) + return false; + New = ResolveExceptionSpec(NewLoc, New); + if (!New) + return false; + // C++0x [except.spec]p3: Two exception-specifications are compatible if: // - both are non-throwing, regardless of their form, // - both have the form noexcept(constant-expression) and the constant- @@ -318,6 +345,7 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, ExceptionSpecificationType NewEST = New->getExceptionSpecType(); assert(OldEST != EST_Delayed && NewEST != EST_Delayed && + OldEST != EST_Uninstantiated && NewEST != EST_Uninstantiated && "Shouldn't see unknown exception specifications here"); // Shortcut the case where both have no spec. @@ -483,6 +511,14 @@ bool Sema::CheckExceptionSpecSubset( if (!SubLoc.isValid()) SubLoc = SuperLoc; + // Resolve the exception specifications, if needed. + Superset = ResolveExceptionSpec(SuperLoc, Superset); + if (!Superset) + return false; + Subset = ResolveExceptionSpec(SubLoc, Subset); + if (!Subset) + return false; + ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType(); // If superset contains everything, we're done. @@ -507,6 +543,7 @@ bool Sema::CheckExceptionSpecSubset( ExceptionSpecificationType SubEST = Subset->getExceptionSpecType(); assert(SuperEST != EST_Delayed && SubEST != EST_Delayed && + SuperEST != EST_Uninstantiated && SubEST != EST_Uninstantiated && "Shouldn't see unknown exception specifications here"); // It does not. If the subset contains everything, we've failed. @@ -726,4 +763,324 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, New->getLocation()); } +static CanThrowResult canSubExprsThrow(Sema &S, const Expr *CE) { + Expr *E = const_cast<Expr*>(CE); + CanThrowResult R = CT_Cannot; + for (Expr::child_range I = E->children(); I && R != CT_Can; ++I) + R = mergeCanThrow(R, S.canThrow(cast<Expr>(*I))); + return R; +} + +static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, + const Decl *D, + bool NullThrows = true) { + if (!D) + return NullThrows ? CT_Can : CT_Cannot; + + // See if we can get a function type from the decl somehow. + const ValueDecl *VD = dyn_cast<ValueDecl>(D); + if (!VD) // If we have no clue what we're calling, assume the worst. + return CT_Can; + + // As an extension, we assume that __attribute__((nothrow)) functions don't + // throw. + if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>()) + return CT_Cannot; + + QualType T = VD->getType(); + const FunctionProtoType *FT; + if ((FT = T->getAs<FunctionProtoType>())) { + } else if (const PointerType *PT = T->getAs<PointerType>()) + FT = PT->getPointeeType()->getAs<FunctionProtoType>(); + else if (const ReferenceType *RT = T->getAs<ReferenceType>()) + FT = RT->getPointeeType()->getAs<FunctionProtoType>(); + else if (const MemberPointerType *MT = T->getAs<MemberPointerType>()) + FT = MT->getPointeeType()->getAs<FunctionProtoType>(); + else if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) + FT = BT->getPointeeType()->getAs<FunctionProtoType>(); + + if (!FT) + return CT_Can; + + FT = S.ResolveExceptionSpec(E->getLocStart(), FT); + if (!FT) + return CT_Can; + + if (FT->getExceptionSpecType() == EST_Delayed) { + // FIXME: Try to resolve a delayed exception spec in ResolveExceptionSpec. + assert(isa<CXXConstructorDecl>(D) && + "only constructor exception specs can be unknown"); + S.Diag(E->getLocStart(), diag::err_exception_spec_unknown) + << E->getSourceRange(); + return CT_Can; + } + + return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can; +} + +static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) { + if (DC->isTypeDependent()) + return CT_Dependent; + + if (!DC->getTypeAsWritten()->isReferenceType()) + return CT_Cannot; + + if (DC->getSubExpr()->isTypeDependent()) + return CT_Dependent; + + return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot; +} + +static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) { + if (DC->isTypeOperand()) + return CT_Cannot; + + Expr *Op = DC->getExprOperand(); + if (Op->isTypeDependent()) + return CT_Dependent; + + const RecordType *RT = Op->getType()->getAs<RecordType>(); + if (!RT) + return CT_Cannot; + + if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic()) + return CT_Cannot; + + if (Op->Classify(S.Context).isPRValue()) + return CT_Cannot; + + return CT_Can; +} + +CanThrowResult Sema::canThrow(const Expr *E) { + // C++ [expr.unary.noexcept]p3: + // [Can throw] if in a potentially-evaluated context the expression would + // contain: + switch (E->getStmtClass()) { + case Expr::CXXThrowExprClass: + // - a potentially evaluated throw-expression + return CT_Can; + + case Expr::CXXDynamicCastExprClass: { + // - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v), + // where T is a reference type, that requires a run-time check + CanThrowResult CT = canDynamicCastThrow(cast<CXXDynamicCastExpr>(E)); + if (CT == CT_Can) + return CT; + return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + } + + case Expr::CXXTypeidExprClass: + // - a potentially evaluated typeid expression applied to a glvalue + // expression whose type is a polymorphic class type + return canTypeidThrow(*this, cast<CXXTypeidExpr>(E)); + + // - a potentially evaluated call to a function, member function, function + // pointer, or member function pointer that does not have a non-throwing + // exception-specification + case Expr::CallExprClass: + case Expr::CXXMemberCallExprClass: + case Expr::CXXOperatorCallExprClass: + case Expr::UserDefinedLiteralClass: { + const CallExpr *CE = cast<CallExpr>(E); + CanThrowResult CT; + if (E->isTypeDependent()) + CT = CT_Dependent; + else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) + CT = CT_Cannot; + else + CT = canCalleeThrow(*this, E, CE->getCalleeDecl()); + if (CT == CT_Can) + return CT; + return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + } + + case Expr::CXXConstructExprClass: + case Expr::CXXTemporaryObjectExprClass: { + CanThrowResult CT = canCalleeThrow(*this, E, + cast<CXXConstructExpr>(E)->getConstructor()); + if (CT == CT_Can) + return CT; + return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + } + + case Expr::LambdaExprClass: { + const LambdaExpr *Lambda = cast<LambdaExpr>(E); + CanThrowResult CT = CT_Cannot; + for (LambdaExpr::capture_init_iterator Cap = Lambda->capture_init_begin(), + CapEnd = Lambda->capture_init_end(); + Cap != CapEnd; ++Cap) + CT = mergeCanThrow(CT, canThrow(*Cap)); + return CT; + } + + case Expr::CXXNewExprClass: { + CanThrowResult CT; + if (E->isTypeDependent()) + CT = CT_Dependent; + else + CT = canCalleeThrow(*this, E, cast<CXXNewExpr>(E)->getOperatorNew()); + if (CT == CT_Can) + return CT; + return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + } + + case Expr::CXXDeleteExprClass: { + CanThrowResult CT; + QualType DTy = cast<CXXDeleteExpr>(E)->getDestroyedType(); + if (DTy.isNull() || DTy->isDependentType()) { + CT = CT_Dependent; + } else { + CT = canCalleeThrow(*this, E, + cast<CXXDeleteExpr>(E)->getOperatorDelete()); + if (const RecordType *RT = DTy->getAs<RecordType>()) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + CT = mergeCanThrow(CT, canCalleeThrow(*this, E, RD->getDestructor())); + } + if (CT == CT_Can) + return CT; + } + return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + } + + case Expr::CXXBindTemporaryExprClass: { + // The bound temporary has to be destroyed again, which might throw. + CanThrowResult CT = canCalleeThrow(*this, E, + cast<CXXBindTemporaryExpr>(E)->getTemporary()->getDestructor()); + if (CT == CT_Can) + return CT; + return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + } + + // ObjC message sends are like function calls, but never have exception + // specs. + case Expr::ObjCMessageExprClass: + case Expr::ObjCPropertyRefExprClass: + case Expr::ObjCSubscriptRefExprClass: + return CT_Can; + + // All the ObjC literals that are implemented as calls are + // potentially throwing unless we decide to close off that + // possibility. + case Expr::ObjCArrayLiteralClass: + case Expr::ObjCDictionaryLiteralClass: + case Expr::ObjCNumericLiteralClass: + return CT_Can; + + // Many other things have subexpressions, so we have to test those. + // Some are simple: + case Expr::ConditionalOperatorClass: + case Expr::CompoundLiteralExprClass: + case Expr::CXXConstCastExprClass: + case Expr::CXXDefaultArgExprClass: + case Expr::CXXReinterpretCastExprClass: + case Expr::DesignatedInitExprClass: + case Expr::ExprWithCleanupsClass: + case Expr::ExtVectorElementExprClass: + case Expr::InitListExprClass: + case Expr::MemberExprClass: + case Expr::ObjCIsaExprClass: + case Expr::ObjCIvarRefExprClass: + case Expr::ParenExprClass: + case Expr::ParenListExprClass: + case Expr::ShuffleVectorExprClass: + case Expr::VAArgExprClass: + return canSubExprsThrow(*this, E); + + // Some might be dependent for other reasons. + case Expr::ArraySubscriptExprClass: + case Expr::BinaryOperatorClass: + case Expr::CompoundAssignOperatorClass: + case Expr::CStyleCastExprClass: + case Expr::CXXStaticCastExprClass: + case Expr::CXXFunctionalCastExprClass: + case Expr::ImplicitCastExprClass: + case Expr::MaterializeTemporaryExprClass: + case Expr::UnaryOperatorClass: { + CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot; + return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + } + + // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms. + case Expr::StmtExprClass: + return CT_Can; + + case Expr::ChooseExprClass: + if (E->isTypeDependent() || E->isValueDependent()) + return CT_Dependent; + return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr(Context)); + + case Expr::GenericSelectionExprClass: + if (cast<GenericSelectionExpr>(E)->isResultDependent()) + return CT_Dependent; + return canThrow(cast<GenericSelectionExpr>(E)->getResultExpr()); + + // Some expressions are always dependent. + case Expr::CXXDependentScopeMemberExprClass: + case Expr::CXXUnresolvedConstructExprClass: + case Expr::DependentScopeDeclRefExprClass: + return CT_Dependent; + + case Expr::AsTypeExprClass: + case Expr::BinaryConditionalOperatorClass: + case Expr::BlockExprClass: + case Expr::CUDAKernelCallExprClass: + case Expr::DeclRefExprClass: + case Expr::ObjCBridgedCastExprClass: + case Expr::ObjCIndirectCopyRestoreExprClass: + case Expr::ObjCProtocolExprClass: + case Expr::ObjCSelectorExprClass: + case Expr::OffsetOfExprClass: + case Expr::PackExpansionExprClass: + case Expr::PseudoObjectExprClass: + case Expr::SubstNonTypeTemplateParmExprClass: + case Expr::SubstNonTypeTemplateParmPackExprClass: + case Expr::UnaryExprOrTypeTraitExprClass: + case Expr::UnresolvedLookupExprClass: + case Expr::UnresolvedMemberExprClass: + // FIXME: Can any of the above throw? If so, when? + return CT_Cannot; + + case Expr::AddrLabelExprClass: + case Expr::ArrayTypeTraitExprClass: + case Expr::AtomicExprClass: + case Expr::BinaryTypeTraitExprClass: + case Expr::TypeTraitExprClass: + case Expr::CXXBoolLiteralExprClass: + case Expr::CXXNoexceptExprClass: + case Expr::CXXNullPtrLiteralExprClass: + case Expr::CXXPseudoDestructorExprClass: + case Expr::CXXScalarValueInitExprClass: + case Expr::CXXThisExprClass: + case Expr::CXXUuidofExprClass: + case Expr::CharacterLiteralClass: + case Expr::ExpressionTraitExprClass: + case Expr::FloatingLiteralClass: + case Expr::GNUNullExprClass: + case Expr::ImaginaryLiteralClass: + case Expr::ImplicitValueInitExprClass: + case Expr::IntegerLiteralClass: + case Expr::ObjCEncodeExprClass: + case Expr::ObjCStringLiteralClass: + case Expr::ObjCBoolLiteralExprClass: + case Expr::OpaqueValueExprClass: + case Expr::PredefinedExprClass: + case Expr::SizeOfPackExprClass: + case Expr::StringLiteralClass: + case Expr::UnaryTypeTraitExprClass: + // These expressions can never throw. + return CT_Cannot; + +#define STMT(CLASS, PARENT) case Expr::CLASS##Class: +#define STMT_RANGE(Base, First, Last) +#define LAST_STMT_RANGE(BASE, FIRST, LAST) +#define EXPR(CLASS, PARENT) +#define ABSTRACT_STMT(STMT) +#include "clang/AST/StmtNodes.inc" + case Expr::NoStmtClass: + llvm_unreachable("Invalid class for expression"); + } + llvm_unreachable("Bogus StmtClass"); +} + } // end namespace clang diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 0d0f2f5..d2e0e6b 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9438,10 +9438,11 @@ ExprResult Sema::VerifyIntegerConstantExpression(Expr *E, PDiag(diag::err_expr_not_ice) << LangOpts.CPlusPlus); } -ExprResult Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, - PartialDiagnostic NotIceDiag, - bool AllowFold, - PartialDiagnostic FoldDiag) { +ExprResult +Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, + const PartialDiagnostic &NotIceDiag, + bool AllowFold, + const PartialDiagnostic &FoldDiag) { SourceLocation DiagLoc = E->getLocStart(); if (getLangOpts().CPlusPlus0x) { @@ -9773,6 +9774,12 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) { // FIXME: Is this really right? if (CurContext == Func) return; + // Instantiate the exception specification for any function which is + // used: CodeGen will need it. + const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>(); + if (FPT && FPT->getExceptionSpecType() == EST_Uninstantiated) + InstantiateExceptionSpec(Loc, Func); + // Implicit instantiation of function templates and member functions of // class templates. if (Func->isImplicitlyInstantiable()) { @@ -11268,22 +11275,6 @@ ExprResult Sema::ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { assert((Kind == tok::kw___objc_yes || Kind == tok::kw___objc_no) && "Unknown Objective-C Boolean value!"); - QualType ObjCBoolLiteralQT = Context.ObjCBuiltinBoolTy; - // signed char is the default type for boolean literals. Use 'BOOL' - // instead, if BOOL typedef is visible in its scope instead. - Decl *TD = - LookupSingleName(TUScope, &Context.Idents.get("BOOL"), - SourceLocation(), LookupOrdinaryName); - if (TypedefDecl *BoolTD = dyn_cast_or_null<TypedefDecl>(TD)) { - QualType QT = BoolTD->getUnderlyingType(); - if (!QT->isIntegralOrUnscopedEnumerationType()) { - Diag(OpLoc, diag::warn_bool_for_boolean_literal) << QT; - Diag(BoolTD->getLocation(), diag::note_previous_declaration); - } - else - ObjCBoolLiteralQT = QT; - } - return Owned(new (Context) ObjCBoolLiteralExpr(Kind == tok::kw___objc_yes, - ObjCBoolLiteralQT, OpLoc)); + Context.ObjCBuiltinBoolTy, OpLoc)); } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 31a8115..af86cb2 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -654,23 +654,44 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, QualType Sema::getCurrentThisType() { DeclContext *DC = getFunctionLevelDeclContext(); - QualType ThisTy; + QualType ThisTy = CXXThisTypeOverride; if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC)) { if (method && method->isInstance()) ThisTy = method->getThisType(Context); - } else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) { - // C++0x [expr.prim]p4: - // Otherwise, if a member-declarator declares a non-static data member - // of a class X, the expression this is a prvalue of type "pointer to X" - // within the optional brace-or-equal-initializer. - Scope *S = getScopeForContext(DC); - if (!S || S->getFlags() & Scope::ThisScope) - ThisTy = Context.getPointerType(Context.getRecordType(RD)); } - + return ThisTy; } +Sema::CXXThisScopeRAII::CXXThisScopeRAII(Sema &S, + Decl *ContextDecl, + unsigned CXXThisTypeQuals, + bool Enabled) + : S(S), OldCXXThisTypeOverride(S.CXXThisTypeOverride), Enabled(false) +{ + if (!Enabled || !ContextDecl) + return; + + CXXRecordDecl *Record = 0; + if (ClassTemplateDecl *Template = dyn_cast<ClassTemplateDecl>(ContextDecl)) + Record = Template->getTemplatedDecl(); + else + Record = cast<CXXRecordDecl>(ContextDecl); + + S.CXXThisTypeOverride + = S.Context.getPointerType( + S.Context.getRecordType(Record).withCVRQualifiers(CXXThisTypeQuals)); + + this->Enabled = true; +} + + +Sema::CXXThisScopeRAII::~CXXThisScopeRAII() { + if (Enabled) { + S.CXXThisTypeOverride = OldCXXThisTypeOverride; + } +} + void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) { // We don't need to capture this in an unevaluated context. if (ExprEvalContexts.back().Context == Unevaluated && !Explicit) @@ -739,6 +760,18 @@ ExprResult Sema::ActOnCXXThis(SourceLocation Loc) { return Owned(new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false)); } +bool Sema::isThisOutsideMemberFunctionBody(QualType BaseType) { + // If we're outside the body of a member function, then we'll have a specified + // type for 'this'. + if (CXXThisTypeOverride.isNull()) + return false; + + // Determine whether we're looking into a class that's currently being + // defined. + CXXRecordDecl *Class = BaseType->getAsCXXRecordDecl(); + return Class && Class->isBeingDefined(); +} + ExprResult Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, SourceLocation LParenLoc, @@ -3102,6 +3135,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, FoundAssign = true; const FunctionProtoType *CPT = Operator->getType()->getAs<FunctionProtoType>(); + CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); + if (!CPT) + return false; if (CPT->getExceptionSpecType() == EST_Delayed) return false; if (!CPT->isNothrow(Self.Context)) @@ -3141,6 +3177,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, FoundConstructor = true; const FunctionProtoType *CPT = Constructor->getType()->getAs<FunctionProtoType>(); + CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); + if (!CPT) + return false; if (CPT->getExceptionSpecType() == EST_Delayed) return false; // FIXME: check whether evaluating default arguments can throw. @@ -3176,6 +3215,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, if (Constructor->isDefaultConstructor()) { const FunctionProtoType *CPT = Constructor->getType()->getAs<FunctionProtoType>(); + CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); + if (!CPT) + return false; if (CPT->getExceptionSpecType() == EST_Delayed) return false; // TODO: check whether evaluating default arguments can throw. @@ -4784,8 +4826,13 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, return Owned(Base); } - // The object type must be complete (or dependent). + // The object type must be complete (or dependent), or + // C++11 [expr.prim.general]p3: + // Unlike the object expression in other contexts, *this is not required to + // be of complete type for purposes of class member access (5.2.5) outside + // the member function body. if (!BaseType->isDependentType() && + !isThisOutsideMemberFunctionBody(BaseType) && RequireCompleteType(OpLoc, BaseType, PDiag(diag::err_incomplete_member_access))) return ExprError(); @@ -5165,9 +5212,9 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, SourceLocation RParen) { + CanThrowResult CanThrow = canThrow(Operand); return Owned(new (Context) CXXNoexceptExpr(Context.BoolTy, Operand, - Operand->CanThrow(Context), - KeyLoc, RParen)); + CanThrow, KeyLoc, RParen)); } ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation, diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index 26b88a2..6c84caa 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -101,16 +101,8 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, DeclContext *DC = SemaRef.getFunctionLevelDeclContext(); - bool isStaticContext = - (!isa<CXXMethodDecl>(DC) || - cast<CXXMethodDecl>(DC)->isStatic()); - - // C++0x [expr.prim]p4: - // Otherwise, if a member-declarator declares a non-static data member - // of a class X, the expression this is a prvalue of type "pointer to X" - // within the optional brace-or-equal-initializer. - if (CurScope->getFlags() & Scope::ThisScope) - isStaticContext = false; + bool isStaticContext = SemaRef.CXXThisTypeOverride.isNull() && + (!isa<CXXMethodDecl>(DC) || cast<CXXMethodDecl>(DC)->isStatic()); if (R.isUnresolvableResult()) return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved; @@ -549,12 +541,13 @@ class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback { } static bool -LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, +LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, SourceRange BaseRange, const RecordType *RTy, SourceLocation OpLoc, CXXScopeSpec &SS, bool HasTemplateArgs) { RecordDecl *RDecl = RTy->getDecl(); - if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), + if (!SemaRef.isThisOutsideMemberFunctionBody(QualType(RTy, 0)) && + SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), SemaRef.PDiag(diag::err_typecheck_incomplete_tag) << BaseRange)) return true; diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 966eb90..f003bdd 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -3165,7 +3165,7 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc, namespace { typedef llvm::StringMap<TypoCorrection, llvm::BumpPtrAllocator> TypoResultsMap; -typedef std::map<unsigned, TypoResultsMap *> TypoEditDistanceMap; +typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap; static const unsigned MaxTypoDistanceResultSets = 5; @@ -3187,14 +3187,6 @@ public: : Typo(Typo->getName()), SemaRef(SemaRef) { } - ~TypoCorrectionConsumer() { - for (TypoEditDistanceMap::iterator I = BestResults.begin(), - IEnd = BestResults.end(); - I != IEnd; - ++I) - delete I->second; - } - virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, bool InBaseClass); void FoundName(StringRef Name); @@ -3212,7 +3204,7 @@ public: bool empty() const { return BestResults.empty(); } TypoCorrection &operator[](StringRef Name) { - return (*BestResults.begin()->second)[Name]; + return BestResults.begin()->second[Name]; } unsigned getBestEditDistance(bool Normalized) { @@ -3276,11 +3268,9 @@ void TypoCorrectionConsumer::addName(StringRef Name, void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) { StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName(); - TypoResultsMap *& Map = BestResults[Correction.getEditDistance(false)]; - if (!Map) - Map = new TypoResultsMap; + TypoResultsMap &Map = BestResults[Correction.getEditDistance(false)]; - TypoCorrection &CurrentCorrection = (*Map)[Name]; + TypoCorrection &CurrentCorrection = Map[Name]; if (!CurrentCorrection || // FIXME: The following should be rolled up into an operator< on // TypoCorrection with a more principled definition. @@ -3289,12 +3279,8 @@ void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) { CurrentCorrection.getAsString(SemaRef.getLangOpts())) CurrentCorrection = Correction; - while (BestResults.size() > MaxTypoDistanceResultSets) { - TypoEditDistanceMap::iterator Last = BestResults.end(); - --Last; - delete Last->second; - BestResults.erase(Last); - } + while (BestResults.size() > MaxTypoDistanceResultSets) + erase(llvm::prior(BestResults.end())); } // Fill the supplied vector with the IdentifierInfo pointers for each piece of @@ -3882,8 +3868,8 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, while (!Consumer.empty()) { TypoCorrectionConsumer::distance_iterator DI = Consumer.begin(); unsigned ED = DI->first; - for (TypoCorrectionConsumer::result_iterator I = DI->second->begin(), - IEnd = DI->second->end(); + for (TypoCorrectionConsumer::result_iterator I = DI->second.begin(), + IEnd = DI->second.end(); I != IEnd; /* Increment in loop. */) { // If the item already has been looked up or is a keyword, keep it. // If a validator callback object was given, drop the correction @@ -3892,7 +3878,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, TypoCorrectionConsumer::result_iterator Prev = I; ++I; if (!isCandidateViable(CCC, Prev->second)) - DI->second->erase(Prev); + DI->second.erase(Prev); continue; } @@ -3911,7 +3897,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, { TypoCorrectionConsumer::result_iterator Next = I; ++Next; - DI->second->erase(I); + DI->second.erase(I); I = Next; } break; @@ -3929,7 +3915,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, I->second.addCorrectionDecl(*TRD); ++I; if (!isCandidateViable(CCC, Prev->second)) - DI->second->erase(Prev); + DI->second.erase(Prev); break; } @@ -3938,14 +3924,14 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, I->second.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>()); ++I; if (!isCandidateViable(CCC, Prev->second)) - DI->second->erase(Prev); + DI->second.erase(Prev); break; } } } - if (DI->second->empty()) + if (DI->second.empty()) Consumer.erase(DI); else if (!getLangOpts().CPlusPlus || QualifiedResults.empty() || !ED) // If there are results in the closest possible bucket, stop @@ -4009,7 +3995,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, // No corrections remain... if (Consumer.empty()) return TypoCorrection(); - TypoResultsMap &BestResults = *Consumer.begin()->second; + TypoResultsMap &BestResults = Consumer.begin()->second; ED = TypoCorrection::NormalizeEditDistance(Consumer.begin()->first); if (ED > 0 && Typo->getName().size() / ED < 3) { @@ -4083,7 +4069,8 @@ std::string TypoCorrection::getAsString(const LangOptions &LO) const { std::string tmpBuffer; llvm::raw_string_ostream PrefixOStream(tmpBuffer); CorrectionNameSpec->print(PrefixOStream, PrintingPolicy(LO)); - return PrefixOStream.str() + CorrectionName.getAsString(); + CorrectionName.printName(PrefixOStream); + return PrefixOStream.str(); } return CorrectionName.getAsString(); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 284c8de..50230f0 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -11150,6 +11150,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, VK_LValue, Found.getDecl(), TemplateArgs); + MarkDeclRefReferenced(DRE); DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1); return DRE; } @@ -11178,6 +11179,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, VK_LValue, Found.getDecl(), TemplateArgs); + MarkDeclRefReferenced(DRE); DRE->setHadMultipleCandidates(MemExpr->getNumDecls() > 1); return DRE; } else { diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index d52c912..0e66329 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -214,6 +214,7 @@ namespace { ObjCMethodDecl *Setter; Selector SetterSelector; + Selector GetterSelector; public: ObjCPropertyOpBuilder(Sema &S, ObjCPropertyRefExpr *refExpr) : @@ -475,8 +476,24 @@ bool ObjCPropertyOpBuilder::findGetter() { // For implicit properties, just trust the lookup we already did. if (RefExpr->isImplicitProperty()) { - Getter = RefExpr->getImplicitPropertyGetter(); - return (Getter != 0); + if ((Getter = RefExpr->getImplicitPropertyGetter())) { + GetterSelector = Getter->getSelector(); + return true; + } + else { + // Must build the getter selector the hard way. + ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter(); + assert(setter && "both setter and getter are null - cannot happen"); + IdentifierInfo *setterName = + setter->getSelector().getIdentifierInfoForSlot(0); + const char *compStr = setterName->getNameStart(); + compStr += 3; + IdentifierInfo *getterName = &S.Context.Idents.get(compStr); + GetterSelector = + S.PP.getSelectorTable().getNullarySelector(getterName); + return false; + + } } ObjCPropertyDecl *prop = RefExpr->getExplicitProperty(); @@ -776,7 +793,7 @@ ObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, assert(RefExpr->isImplicitProperty()); S.Diag(opcLoc, diag::err_nogetter_property_incdec) << unsigned(UnaryOperator::isDecrementOp(opcode)) - << RefExpr->getImplicitPropertyGetter()->getSelector() // FIXME! + << GetterSelector << op->getSourceRange(); return ExprError(); } @@ -1300,6 +1317,11 @@ static Expr *stripOpaqueValuesFromPseudoObjectRef(Sema &S, Expr *E) { Expr *opaqueRef = E->IgnoreParens(); if (ObjCPropertyRefExpr *refExpr = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { + // Class and super property references don't have opaque values in them. + if (refExpr->isClassReceiver() || refExpr->isSuperReceiver()) + return E; + + assert(refExpr->isObjectReceiver() && "Unknown receiver kind?"); OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(refExpr->getBase()); return ObjCPropertyRefRebuilder(S, baseOVE->getSourceExpr()).rebuild(E); } else if (ObjCSubscriptRefExpr *refExpr diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 97c8eb0..9052278 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -345,7 +345,6 @@ Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, StmtResult Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, SourceLocation ColonLoc, Stmt *SubStmt) { - // If the label was multiply defined, reject it now. if (TheDecl->getStmt()) { Diag(IdentLoc, diag::err_redefinition_of_label) << TheDecl->getDeclName(); @@ -361,6 +360,16 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, return Owned(LS); } +StmtResult Sema::ActOnAttributedStmt(SourceLocation AttrLoc, + const AttrVec &Attrs, + Stmt *SubStmt) { + // Fill in the declaration and return it. Variable length will require to + // change this to AttributedStmt::Create(Context, ....); + // and probably using ArrayRef + AttributedStmt *LS = new (Context) AttributedStmt(AttrLoc, Attrs, SubStmt); + return Owned(LS); +} + StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar, Stmt *thenStmt, SourceLocation ElseLoc, diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp new file mode 100644 index 0000000..21c3297 --- /dev/null +++ b/lib/Sema/SemaStmtAttr.cpp @@ -0,0 +1,48 @@ +//===--- SemaStmtAttr.cpp - Statement Attribute Handling ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements stmt-related attribute processing. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaInternal.h" +#include "TargetAttributesSema.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/Lookup.h" +#include "llvm/ADT/StringExtras.h" +using namespace clang; +using namespace sema; + + +static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A) { + switch (A.getKind()) { + default: + // if we're here, then we parsed an attribute, but didn't recognize it as a + // statement attribute => it is declaration attribute + S.Diag(A.getRange().getBegin(), diag::warn_attribute_invalid_on_stmt) << + A.getName()->getName(); + return 0; + } +} + +StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList, + SourceRange Range) { + AttrVec Attrs; + for (const AttributeList* l = AttrList; l; l = l->getNext()) { + if (Attr *a = ProcessStmtAttribute(*this, S, *l)) + Attrs.push_back(a); + } + + if (Attrs.empty()) + return S; + + return ActOnAttributedStmt(Range.getBegin(), Attrs, S); +} diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index ff8c4da..51ce2a1 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2496,6 +2496,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); + Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); ArgType = SemaRef.SubstType(ArgType, AllTemplateArgs, Param->getDefaultArgumentLoc(), Param->getDeclName()); @@ -2544,6 +2545,8 @@ SubstDefaultTemplateArgument(Sema &SemaRef, Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); + Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); + EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); return SemaRef.SubstExpr(Param->getDefaultArgument(), AllTemplateArgs); } @@ -2591,6 +2594,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); + Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); // Substitute into the nested-name-specifier first, QualifierLoc = Param->getDefaultArgument().getTemplateQualifierLoc(); if (QualifierLoc) { diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 2ea1e6f..d68e464 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -2310,23 +2310,42 @@ Sema::SubstituteExplicitTemplateArguments( // explicitly-specified template arguments. If the function has a trailing // return type, substitute it after the arguments to ensure we substitute // in lexical order. - if (Proto->hasTrailingReturn() && - SubstParmTypes(Function->getLocation(), - Function->param_begin(), Function->getNumParams(), - MultiLevelTemplateArgumentList(*ExplicitArgumentList), - ParamTypes)) - return TDK_SubstitutionFailure; - + if (Proto->hasTrailingReturn()) { + if (SubstParmTypes(Function->getLocation(), + Function->param_begin(), Function->getNumParams(), + MultiLevelTemplateArgumentList(*ExplicitArgumentList), + ParamTypes)) + return TDK_SubstitutionFailure; + } + // Instantiate the return type. // FIXME: exception-specifications? - QualType ResultType - = SubstType(Proto->getResultType(), - MultiLevelTemplateArgumentList(*ExplicitArgumentList), - Function->getTypeSpecStartLoc(), - Function->getDeclName()); - if (ResultType.isNull() || Trap.hasErrorOccurred()) - return TDK_SubstitutionFailure; - + QualType ResultType; + { + // C++11 [expr.prim.general]p3: + // If a declaration declares a member function or member function + // template of a class X, the expression this is a prvalue of type + // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq + // and the end of the function-definition, member-declarator, or + // declarator. + unsigned ThisTypeQuals = 0; + CXXRecordDecl *ThisContext = 0; + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) { + ThisContext = Method->getParent(); + ThisTypeQuals = Method->getTypeQualifiers(); + } + + CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals, + getLangOpts().CPlusPlus0x); + + ResultType = SubstType(Proto->getResultType(), + MultiLevelTemplateArgumentList(*ExplicitArgumentList), + Function->getTypeSpecStartLoc(), + Function->getDeclName()); + if (ResultType.isNull() || Trap.hasErrorOccurred()) + return TDK_SubstitutionFailure; + } + // Instantiate the types of each of the function parameters given the // explicitly-specified template arguments if we didn't do so earlier. if (!Proto->hasTrailingReturn() && diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 4740145..128dc2f 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -153,6 +153,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const { switch (Kind) { case TemplateInstantiation: + case ExceptionSpecInstantiation: case DefaultTemplateArgumentInstantiation: case DefaultFunctionArgumentInstantiation: return true; @@ -190,6 +191,29 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, } } +Sema::InstantiatingTemplate:: +InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + FunctionDecl *Entity, ExceptionSpecification, + SourceRange InstantiationRange) + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ + Invalid = CheckInstantiationDepth(PointOfInstantiation, + InstantiationRange); + if (!Invalid) { + ActiveTemplateInstantiation Inst; + Inst.Kind = ActiveTemplateInstantiation::ExceptionSpecInstantiation; + Inst.PointOfInstantiation = PointOfInstantiation; + Inst.Entity = reinterpret_cast<uintptr_t>(Entity); + Inst.TemplateArgs = 0; + Inst.NumTemplateArgs = 0; + Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + } +} + Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template, @@ -592,6 +616,13 @@ void Sema::PrintInstantiationStack() { << Active->InstantiationRange; break; } + + case ActiveTemplateInstantiation::ExceptionSpecInstantiation: + Diags.Report(Active->PointOfInstantiation, + diag::note_template_exception_spec_instantiation_here) + << cast<FunctionDecl>((Decl *)Active->Entity) + << Active->InstantiationRange; + break; } } } @@ -609,6 +640,7 @@ llvm::Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { switch(Active->Kind) { case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: case ActiveTemplateInstantiation::TemplateInstantiation: + case ActiveTemplateInstantiation::ExceptionSpecInstantiation: // This is a template instantiation, so there is no SFINAE. return llvm::Optional<TemplateDeductionInfo *>(); @@ -789,6 +821,11 @@ namespace { QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL); + QualType TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL, + CXXRecordDecl *ThisContext, + unsigned ThisTypeQuals); + ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, int indexAdjustment, llvm::Optional<unsigned> NumExpansions, @@ -1211,6 +1248,16 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, return inherited::TransformFunctionProtoType(TLB, TL); } +QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL, + CXXRecordDecl *ThisContext, + unsigned ThisTypeQuals) { + // We need a local instantiation scope for this function prototype. + LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); + return inherited::TransformFunctionProtoType(TLB, TL, ThisContext, + ThisTypeQuals); +} + ParmVarDecl * TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm, int indexAdjustment, @@ -1446,7 +1493,9 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &Args, SourceLocation Loc, - DeclarationName Entity) { + DeclarationName Entity, + CXXRecordDecl *ThisContext, + unsigned ThisTypeQuals) { assert(!ActiveTemplateInstantiations.empty() && "Cannot perform an instantiation without some context on the " "instantiation stack"); @@ -1461,7 +1510,14 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, TypeLoc TL = T->getTypeLoc(); TLB.reserve(TL.getFullDataSize()); - QualType Result = Instantiator.TransformType(TLB, TL); + QualType Result; + + if (FunctionProtoTypeLoc *Proto = dyn_cast<FunctionProtoTypeLoc>(&TL)) { + Result = Instantiator.TransformFunctionProtoType(TLB, *Proto, ThisContext, + ThisTypeQuals); + } else { + Result = Instantiator.TransformType(TLB, TL); + } if (Result.isNull()) return 0; @@ -1878,24 +1934,33 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, CheckCompletedCXXClass(Instantiation); // Attach any in-class member initializers now the class is complete. - for (unsigned I = 0, N = FieldsWithMemberInitializers.size(); I != N; ++I) { - FieldDecl *OldField = FieldsWithMemberInitializers[I].first; - FieldDecl *NewField = FieldsWithMemberInitializers[I].second; - Expr *OldInit = OldField->getInClassInitializer(); - - ExprResult NewInit = SubstInitializer(OldInit, TemplateArgs, - /*CXXDirectInit=*/false); - if (NewInit.isInvalid()) - NewField->setInvalidDecl(); - else { - Expr *Init = NewInit.take(); - assert(Init && "no-argument initializer in class"); - assert(!isa<ParenListExpr>(Init) && "call-style init in class"); - ActOnCXXInClassMemberInitializer(NewField, - Init->getSourceRange().getBegin(), Init); + { + // C++11 [expr.prim.general]p4: + // Otherwise, if a member-declarator declares a non-static data member + // (9.2) of a class X, the expression this is a prvalue of type "pointer + // to X" within the optional brace-or-equal-initializer. It shall not + // appear elsewhere in the member-declarator. + CXXThisScopeRAII ThisScope(*this, Instantiation, (unsigned)0); + + for (unsigned I = 0, N = FieldsWithMemberInitializers.size(); I != N; ++I) { + FieldDecl *OldField = FieldsWithMemberInitializers[I].first; + FieldDecl *NewField = FieldsWithMemberInitializers[I].second; + Expr *OldInit = OldField->getInClassInitializer(); + + ExprResult NewInit = SubstInitializer(OldInit, TemplateArgs, + /*CXXDirectInit=*/false); + if (NewInit.isInvalid()) + NewField->setInvalidDecl(); + else { + Expr *Init = NewInit.take(); + assert(Init && "no-argument initializer in class"); + assert(!isa<ParenListExpr>(Init) && "call-style init in class"); + ActOnCXXInClassMemberInitializer(NewField, + Init->getSourceRange().getBegin(), + Init); + } } } - // Instantiate late parsed attributes, and attach them to their decls. // See Sema::InstantiateAttrs for (LateInstantiatedAttrVec::iterator I = LateAttrs.begin(), diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 8afe7ac..c7bd99c 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2141,10 +2141,19 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, TypeSourceInfo *OldTInfo = D->getTypeSourceInfo(); assert(OldTInfo && "substituting function without type source info"); assert(Params.empty() && "parameter vector is non-empty at start"); + + CXXRecordDecl *ThisContext = 0; + unsigned ThisTypeQuals = 0; + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + ThisContext = Method->getParent(); + ThisTypeQuals = Method->getTypeQualifiers(); + } + TypeSourceInfo *NewTInfo = SemaRef.SubstFunctionDeclType(OldTInfo, TemplateArgs, D->getTypeSpecStartLoc(), - D->getDeclName()); + D->getDeclName(), + ThisContext, ThisTypeQuals); if (!NewTInfo) return 0; @@ -2206,6 +2215,195 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, return NewTInfo; } +/// Introduce the instantiated function parameters into the local +/// instantiation scope, and set the parameter names to those used +/// in the template. +static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, + const FunctionDecl *PatternDecl, + LocalInstantiationScope &Scope, + const MultiLevelTemplateArgumentList &TemplateArgs) { + unsigned FParamIdx = 0; + for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) { + const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I); + if (!PatternParam->isParameterPack()) { + // Simple case: not a parameter pack. + assert(FParamIdx < Function->getNumParams()); + ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); + FunctionParam->setDeclName(PatternParam->getDeclName()); + Scope.InstantiatedLocal(PatternParam, FunctionParam); + ++FParamIdx; + continue; + } + + // Expand the parameter pack. + Scope.MakeInstantiatedLocalArgPack(PatternParam); + unsigned NumArgumentsInExpansion + = S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs); + for (unsigned Arg = 0; Arg < NumArgumentsInExpansion; ++Arg) { + ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); + FunctionParam->setDeclName(PatternParam->getDeclName()); + Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam); + ++FParamIdx; + } + } +} + +static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New, + const FunctionProtoType *Proto, + const MultiLevelTemplateArgumentList &TemplateArgs) { + assert(Proto->getExceptionSpecType() != EST_Uninstantiated); + + // C++11 [expr.prim.general]p3: + // If a declaration declares a member function or member function + // template of a class X, the expression this is a prvalue of type + // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq + // and the end of the function-definition, member-declarator, or + // declarator. + CXXRecordDecl *ThisContext = 0; + unsigned ThisTypeQuals = 0; + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(New)) { + ThisContext = Method->getParent(); + ThisTypeQuals = Method->getTypeQualifiers(); + } + Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals, + SemaRef.getLangOpts().CPlusPlus0x); + + // The function has an exception specification or a "noreturn" + // attribute. Substitute into each of the exception types. + SmallVector<QualType, 4> Exceptions; + for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) { + // FIXME: Poor location information! + if (const PackExpansionType *PackExpansion + = Proto->getExceptionType(I)->getAs<PackExpansionType>()) { + // We have a pack expansion. Instantiate it. + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), + Unexpanded); + assert(!Unexpanded.empty() && + "Pack expansion without parameter packs?"); + + bool Expand = false; + bool RetainExpansion = false; + llvm::Optional<unsigned> NumExpansions + = PackExpansion->getNumExpansions(); + if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(), + SourceRange(), + Unexpanded, + TemplateArgs, + Expand, + RetainExpansion, + NumExpansions)) + break; + + if (!Expand) { + // We can't expand this pack expansion into separate arguments yet; + // just substitute into the pattern and create a new pack expansion + // type. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); + QualType T = SemaRef.SubstType(PackExpansion->getPattern(), + TemplateArgs, + New->getLocation(), New->getDeclName()); + if (T.isNull()) + break; + + T = SemaRef.Context.getPackExpansionType(T, NumExpansions); + Exceptions.push_back(T); + continue; + } + + // Substitute into the pack expansion pattern for each template + bool Invalid = false; + for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx); + + QualType T = SemaRef.SubstType(PackExpansion->getPattern(), + TemplateArgs, + New->getLocation(), New->getDeclName()); + if (T.isNull()) { + Invalid = true; + break; + } + + Exceptions.push_back(T); + } + + if (Invalid) + break; + + continue; + } + + QualType T + = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs, + New->getLocation(), New->getDeclName()); + if (T.isNull() || + SemaRef.CheckSpecifiedExceptionType(T, New->getLocation())) + continue; + + Exceptions.push_back(T); + } + Expr *NoexceptExpr = 0; + if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) { + EnterExpressionEvaluationContext Unevaluated(SemaRef, + Sema::ConstantEvaluated); + ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs); + if (E.isUsable()) + E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart()); + + if (E.isUsable()) { + NoexceptExpr = E.take(); + if (!NoexceptExpr->isTypeDependent() && + !NoexceptExpr->isValueDependent()) + NoexceptExpr = SemaRef.VerifyIntegerConstantExpression(NoexceptExpr, + 0, SemaRef.PDiag(diag::err_noexcept_needs_constant_expression), + /*AllowFold*/ false).take(); + } + } + + // Rebuild the function type + const FunctionProtoType *NewProto + = New->getType()->getAs<FunctionProtoType>(); + assert(NewProto && "Template instantiation without function prototype?"); + + FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo(); + EPI.ExceptionSpecType = Proto->getExceptionSpecType(); + EPI.NumExceptions = Exceptions.size(); + EPI.Exceptions = Exceptions.data(); + EPI.NoexceptExpr = NoexceptExpr; + + New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(), + NewProto->arg_type_begin(), + NewProto->getNumArgs(), + EPI)); +} + +void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, + FunctionDecl *Decl) { + const FunctionProtoType *Proto = Decl->getType()->castAs<FunctionProtoType>(); + if (Proto->getExceptionSpecType() != EST_Uninstantiated) + return; + + InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl, + InstantiatingTemplate::ExceptionSpecification()); + if (Inst) + return; + + // Enter the scope of this instantiation. We don't use + // PushDeclContext because we don't have a scope. + Sema::ContextRAII savedContext(*this, Decl); + LocalInstantiationScope Scope(*this); + + MultiLevelTemplateArgumentList TemplateArgs = + getTemplateInstantiationArgs(Decl, 0, /*RelativeToPrimary*/true); + + FunctionDecl *Template = Proto->getExceptionSpecTemplate(); + addInstantiatedParametersToScope(*this, Decl, Template, Scope, TemplateArgs); + + ::InstantiateExceptionSpec(*this, Decl, + Template->getType()->castAs<FunctionProtoType>(), + TemplateArgs); +} + /// \brief Initializes the common fields of an instantiation function /// declaration (New) from the corresponding fields of its template (Tmpl). /// @@ -2243,119 +2441,37 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, assert(Proto && "Function template without prototype?"); if (Proto->hasExceptionSpec() || Proto->getNoReturnAttr()) { - // The function has an exception specification or a "noreturn" - // attribute. Substitute into each of the exception types. - SmallVector<QualType, 4> Exceptions; - for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) { - // FIXME: Poor location information! - if (const PackExpansionType *PackExpansion - = Proto->getExceptionType(I)->getAs<PackExpansionType>()) { - // We have a pack expansion. Instantiate it. - SmallVector<UnexpandedParameterPack, 2> Unexpanded; - SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), - Unexpanded); - assert(!Unexpanded.empty() && - "Pack expansion without parameter packs?"); - - bool Expand = false; - bool RetainExpansion = false; - llvm::Optional<unsigned> NumExpansions - = PackExpansion->getNumExpansions(); - if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(), - SourceRange(), - Unexpanded, - TemplateArgs, - Expand, - RetainExpansion, - NumExpansions)) - break; - - if (!Expand) { - // We can't expand this pack expansion into separate arguments yet; - // just substitute into the pattern and create a new pack expansion - // type. - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); - QualType T = SemaRef.SubstType(PackExpansion->getPattern(), - TemplateArgs, - New->getLocation(), New->getDeclName()); - if (T.isNull()) - break; - - T = SemaRef.Context.getPackExpansionType(T, NumExpansions); - Exceptions.push_back(T); - continue; - } - - // Substitute into the pack expansion pattern for each template - bool Invalid = false; - for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx); - - QualType T = SemaRef.SubstType(PackExpansion->getPattern(), - TemplateArgs, - New->getLocation(), New->getDeclName()); - if (T.isNull()) { - Invalid = true; - break; - } - - Exceptions.push_back(T); - } - - if (Invalid) - break; - - continue; - } - - QualType T - = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs, - New->getLocation(), New->getDeclName()); - if (T.isNull() || - SemaRef.CheckSpecifiedExceptionType(T, New->getLocation())) - continue; - - Exceptions.push_back(T); - } - Expr *NoexceptExpr = 0; - if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) { - EnterExpressionEvaluationContext Unevaluated(SemaRef, - Sema::ConstantEvaluated); - ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs); - if (E.isUsable()) - E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart()); - - if (E.isUsable()) { - NoexceptExpr = E.take(); - if (!NoexceptExpr->isTypeDependent() && - !NoexceptExpr->isValueDependent()) - NoexceptExpr = SemaRef.VerifyIntegerConstantExpression(NoexceptExpr, - 0, SemaRef.PDiag(diag::err_noexcept_needs_constant_expression), - /*AllowFold*/ false).take(); - } - } - - // Rebuild the function type - FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); - EPI.ExceptionSpecType = Proto->getExceptionSpecType(); - EPI.NumExceptions = Exceptions.size(); - EPI.Exceptions = Exceptions.data(); - EPI.NoexceptExpr = NoexceptExpr; - EPI.ExtInfo = Proto->getExtInfo(); - const FunctionProtoType *NewProto - = New->getType()->getAs<FunctionProtoType>(); - assert(NewProto && "Template instantiation without function prototype?"); - New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(), - NewProto->arg_type_begin(), - NewProto->getNumArgs(), - EPI)); + // DR1330: In C++11, defer instantiation of a non-trivial + // exception specification. + if (SemaRef.getLangOpts().CPlusPlus0x && + EPI.ExceptionSpecType != EST_None && + EPI.ExceptionSpecType != EST_DynamicNone && + EPI.ExceptionSpecType != EST_BasicNoexcept) { + FunctionDecl *ExceptionSpecTemplate = Tmpl; + if (EPI.ExceptionSpecType == EST_Uninstantiated) + ExceptionSpecTemplate = EPI.ExceptionSpecTemplate; + + // Mark the function has having an uninstantiated exception specification. + const FunctionProtoType *NewProto + = New->getType()->getAs<FunctionProtoType>(); + assert(NewProto && "Template instantiation without function prototype?"); + EPI = NewProto->getExtProtoInfo(); + EPI.ExceptionSpecType = EST_Uninstantiated; + EPI.ExceptionSpecDecl = New; + EPI.ExceptionSpecTemplate = ExceptionSpecTemplate; + New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(), + NewProto->arg_type_begin(), + NewProto->getNumArgs(), + EPI)); + } else { + ::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs); + } } - const FunctionDecl* Definition = Tmpl; - // Get the definition. Leaves the variable unchanged if undefined. + const FunctionDecl *Definition = Tmpl; Tmpl->isDefined(Definition); SemaRef.InstantiateAttrs(TemplateArgs, Definition, New, @@ -2513,33 +2629,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(Function, 0, false, PatternDecl); - // Introduce the instantiated function parameters into the local - // instantiation scope, and set the parameter names to those used - // in the template. - unsigned FParamIdx = 0; - for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) { - const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I); - if (!PatternParam->isParameterPack()) { - // Simple case: not a parameter pack. - assert(FParamIdx < Function->getNumParams()); - ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); - FunctionParam->setDeclName(PatternParam->getDeclName()); - Scope.InstantiatedLocal(PatternParam, FunctionParam); - ++FParamIdx; - continue; - } - - // Expand the parameter pack. - Scope.MakeInstantiatedLocalArgPack(PatternParam); - unsigned NumArgumentsInExpansion - = getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs); - for (unsigned Arg = 0; Arg < NumArgumentsInExpansion; ++Arg) { - ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); - FunctionParam->setDeclName(PatternParam->getDeclName()); - Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam); - ++FParamIdx; - } - } + addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope, + TemplateArgs); if (PatternDecl->isDefaulted()) { ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index c41df82..d0906de 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -561,7 +561,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, /*const qualifier*/SourceLocation(), /*volatile qualifier*/SourceLocation(), /*mutable qualifier*/SourceLocation(), - /*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0, + /*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0, 0, /*parens*/ loc, loc, declarator)); @@ -2371,34 +2371,33 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, EPI.ConsumedArguments = ConsumedArguments.data(); SmallVector<QualType, 4> Exceptions; - EPI.ExceptionSpecType = FTI.getExceptionSpecType(); + SmallVector<ParsedType, 2> DynamicExceptions; + SmallVector<SourceRange, 2> DynamicExceptionRanges; + Expr *NoexceptExpr = 0; + if (FTI.getExceptionSpecType() == EST_Dynamic) { - Exceptions.reserve(FTI.NumExceptions); - for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) { - // FIXME: Preserve type source info. - QualType ET = S.GetTypeFromParser(FTI.Exceptions[ei].Ty); - // Check that the type is valid for an exception spec, and - // drop it if not. - if (!S.CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range)) - Exceptions.push_back(ET); + // FIXME: It's rather inefficient to have to split into two vectors + // here. + unsigned N = FTI.NumExceptions; + DynamicExceptions.reserve(N); + DynamicExceptionRanges.reserve(N); + for (unsigned I = 0; I != N; ++I) { + DynamicExceptions.push_back(FTI.Exceptions[I].Ty); + DynamicExceptionRanges.push_back(FTI.Exceptions[I].Range); } - EPI.NumExceptions = Exceptions.size(); - EPI.Exceptions = Exceptions.data(); } else if (FTI.getExceptionSpecType() == EST_ComputedNoexcept) { - // If an error occurred, there's no expression here. - if (Expr *NoexceptExpr = FTI.NoexceptExpr) { - assert((NoexceptExpr->isTypeDependent() || - NoexceptExpr->getType()->getCanonicalTypeUnqualified() == - Context.BoolTy) && - "Parser should have made sure that the expression is boolean"); - if (!NoexceptExpr->isValueDependent()) - NoexceptExpr = S.VerifyIntegerConstantExpression(NoexceptExpr, 0, - S.PDiag(diag::err_noexcept_needs_constant_expression), - /*AllowFold*/ false).take(); - EPI.NoexceptExpr = NoexceptExpr; - } - } else if (FTI.getExceptionSpecType() == EST_None && - ImplicitlyNoexcept && chunkIndex == 0) { + NoexceptExpr = FTI.NoexceptExpr; + } + + S.checkExceptionSpecification(FTI.getExceptionSpecType(), + DynamicExceptions, + DynamicExceptionRanges, + NoexceptExpr, + Exceptions, + EPI); + + if (FTI.getExceptionSpecType() == EST_None && + ImplicitlyNoexcept && chunkIndex == 0) { // Only the outermost chunk is marked noexcept, of course. EPI.ExceptionSpecType = EST_BasicNoexcept; } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index fdb861e..a66378e 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -522,6 +522,11 @@ public: QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); #include "clang/AST/TypeLocNodes.def" + QualType TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL, + CXXRecordDecl *ThisContext, + unsigned ThisTypeQuals); + StmtResult TransformSEHHandler(Stmt *Handler); @@ -1044,6 +1049,15 @@ public: return SemaRef.ActOnLabelStmt(IdentLoc, L, ColonLoc, SubStmt); } + /// \brief Build a new label statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + StmtResult RebuildAttributedStmt(SourceLocation AttrLoc, const AttrVec &Attrs, + Stmt *SubStmt) { + return SemaRef.ActOnAttributedStmt(AttrLoc, Attrs, SubStmt); + } + /// \brief Build a new "if" statement. /// /// By default, performs semantic analysis to build the new statement. @@ -4156,12 +4170,18 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL) { + return getDerived().TransformFunctionProtoType(TLB, TL, 0, 0); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL, + CXXRecordDecl *ThisContext, + unsigned ThisTypeQuals) { // Transform the parameters and return type. // - // We instantiate in source order, with the return type first followed by - // the parameters, because users tend to expect this (even if they shouldn't - // rely on it!). - // + // We are required to instantiate the params and return type in source order. // When the function has a trailing return type, we instantiate the // parameters before the return type, since the return type can then refer // to the parameters themselves (via decltype, sizeof, etc.). @@ -4180,9 +4200,19 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, ParamTypes, &ParamDecls)) return QualType(); - ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); - if (ResultType.isNull()) - return QualType(); + { + // C++11 [expr.prim.general]p3: + // If a declaration declares a member function or member function + // template of a class X, the expression this is a prvalue of type + // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq + // and the end of the function-definition, member-declarator, or + // declarator. + Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals); + + ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); + if (ResultType.isNull()) + return QualType(); + } } else { ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); @@ -4197,6 +4227,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, return QualType(); } + // FIXME: Need to transform the exception-specification too. + QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getResultType() || @@ -5154,8 +5186,8 @@ TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) { S->getDecl()); if (!LD) return StmtError(); - - + + // FIXME: Pass the real colon location in. return getDerived().RebuildLabelStmt(S->getIdentLoc(), cast<LabelDecl>(LD), SourceLocation(), @@ -5164,6 +5196,22 @@ TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) { template<typename Derived> StmtResult +TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) { + StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt()); + if (SubStmt.isInvalid()) + return StmtError(); + + // TODO: transform attributes + if (SubStmt.get() == S->getSubStmt() /* && attrs are the same */) + return S; + + return getDerived().RebuildAttributedStmt(S->getAttrLoc(), + S->getAttrs(), + SubStmt.get()); +} + +template<typename Derived> +StmtResult TreeTransform<Derived>::TransformIfStmt(IfStmt *S) { // Transform the condition ExprResult Cond; |