diff options
Diffstat (limited to 'lib/Sema')
27 files changed, 5106 insertions, 1412 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index e482172..9efae61 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -196,7 +196,12 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { continue; } Expr *CEE = C->getCallee()->IgnoreParenCasts(); - if (getFunctionExtInfo(CEE->getType()).getNoReturn()) { + QualType calleeType = CEE->getType(); + if (calleeType == AC.getASTContext().BoundMemberTy) { + calleeType = Expr::findBoundMemberType(CEE); + assert(!calleeType.isNull() && "analyzing unresolved call?"); + } + if (getFunctionExtInfo(calleeType).getNoReturn()) { NoReturnEdge = true; HasFakeEdge = true; } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index 0f20d10..5be16e7 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -309,6 +309,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_typeofExpr: return "typeof"; case DeclSpec::TST_auto: return "auto"; case DeclSpec::TST_decltype: return "(decltype)"; + case DeclSpec::TST_underlyingType: return "__underlying_type"; case DeclSpec::TST_unknown_anytype: return "__unknown_anytype"; case DeclSpec::TST_error: return "(error)"; } diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index 867d78f..ae154aa 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -15,6 +15,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtCXX.h" #include "llvm/ADT/BitVector.h" @@ -126,18 +127,45 @@ static std::pair<unsigned,unsigned> InDiag = diag::note_protected_by_cleanup; OutDiag = diag::note_exits_cleanup; } else if (isCPlusPlus) { - // FIXME: In C++0x, we have to check more conditions than "did we - // just give it an initializer?". See 6.7p3. - if (VD->hasLocalStorage() && VD->hasInit()) - InDiag = diag::note_protected_by_variable_init; - - CanQualType T = VD->getType()->getCanonicalTypeUnqualified(); + if (!VD->hasLocalStorage()) + return std::make_pair(InDiag, OutDiag); + + ASTContext &Context = D->getASTContext(); + QualType T = Context.getBaseElementType(VD->getType()); if (!T->isDependentType()) { - while (CanQual<ArrayType> AT = T->getAs<ArrayType>()) - T = AT->getElementType(); - if (CanQual<RecordType> RT = T->getAs<RecordType>()) - if (!cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor()) - OutDiag = diag::note_exits_dtor; + // C++0x [stmt.dcl]p3: + // A program that jumps from a point where a variable with automatic + // storage duration is not in scope to a point where it is in scope + // is ill-formed unless the variable has scalar type, class type with + // a trivial default constructor and a trivial destructor, a + // cv-qualified version of one of these types, or an array of one of + // the preceding types and is declared without an initializer (8.5). + // Check whether this is a C++ class. + CXXRecordDecl *Record = T->getAsCXXRecordDecl(); + + if (const Expr *Init = VD->getInit()) { + bool CallsTrivialConstructor = false; + if (Record) { + // FIXME: With generalized initializer lists, this may + // classify "X x{};" as having no initializer. + if (const CXXConstructExpr *Construct + = dyn_cast<CXXConstructExpr>(Init)) + if (const CXXConstructorDecl *Constructor + = Construct->getConstructor()) + if ((Context.getLangOptions().CPlusPlus0x + ? Record->hasTrivialDefaultConstructor() + : Record->isPOD()) && + Constructor->isDefaultConstructor()) + CallsTrivialConstructor = true; + } + + if (!CallsTrivialConstructor) + InDiag = diag::note_protected_by_variable_init; + } + + // Note whether we have a class with a non-trivial destructor. + if (Record && !Record->hasTrivialDestructor()) + OutDiag = diag::note_exits_dtor; } } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 7707fb1..8297b31 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -31,6 +31,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/PartialDiagnostic.h" @@ -377,30 +378,22 @@ void Sema::ActOnEndOfTranslationUnit() { } } - bool SomethingChanged; - do { - SomethingChanged = false; - - // If DefinedUsedVTables ends up marking any virtual member functions it - // might lead to more pending template instantiations, which we then need - // to instantiate. - if (DefineUsedVTables()) - SomethingChanged = true; - - // C++: Perform implicit template instantiations. - // - // FIXME: When we perform these implicit instantiations, we do not - // carefully keep track of the point of instantiation (C++ [temp.point]). - // This means that name lookup that occurs within the template - // instantiation will always happen at the end of the translation unit, - // so it will find some names that should not be found. Although this is - // common behavior for C++ compilers, it is technically wrong. In the - // future, we either need to be able to filter the results of name lookup - // or we need to perform template instantiations earlier. - if (PerformPendingInstantiations()) - SomethingChanged = true; - - } while (SomethingChanged); + // If DefinedUsedVTables ends up marking any virtual member functions it + // might lead to more pending template instantiations, which we then need + // to instantiate. + DefineUsedVTables(); + + // C++: Perform implicit template instantiations. + // + // FIXME: When we perform these implicit instantiations, we do not + // carefully keep track of the point of instantiation (C++ [temp.point]). + // This means that name lookup that occurs within the template + // instantiation will always happen at the end of the translation unit, + // so it will find some names that should not be found. Although this is + // common behavior for C++ compilers, it is technically wrong. In the + // future, we either need to be able to filter the results of name lookup + // or we need to perform template instantiations earlier. + PerformPendingInstantiations(); } // Remove file scoped decls that turned out to be used. @@ -473,6 +466,12 @@ void Sema::ActOnEndOfTranslationUnit() { } + if (LangOpts.CPlusPlus0x && + Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle, + SourceLocation()) + != Diagnostic::Ignored) + CheckDelegatingCtorCycles(); + // If there were errors, disable 'unused' warnings since they will mostly be // noise. if (!Diags.hasErrorOccurred()) { @@ -570,9 +569,12 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { break; case DiagnosticIDs::SFINAE_AccessControl: - // Unless access checking is specifically called out as a SFINAE - // error, report this diagnostic. - if (!SemaRef.AccessCheckingSFINAE) + // Per C++ Core Issue 1170, access control is part of SFINAE. + // Additionally, the AccessCheckingSFINAE flag can be used to temporary + // make access control a part of SFINAE for the purposes of checking + // type traits. + if (!SemaRef.AccessCheckingSFINAE && + !SemaRef.getLangOptions().CPlusPlus0x) break; case DiagnosticIDs::SFINAE_SubstitutionFailure: @@ -763,3 +765,101 @@ void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const { OS << '\n'; } + +/// \brief Figure out if an expression could be turned into a call. +/// +/// Use this when trying to recover from an error where the programmer may have +/// written just the name of a function instead of actually calling it. +/// +/// \param E - The expression to examine. +/// \param ZeroArgCallReturnTy - If the expression can be turned into a call +/// with no arguments, this parameter is set to the type returned by such a +/// call; otherwise, it is set to an empty QualType. +/// \param NonTemplateOverloads - If the expression is an overloaded function +/// name, this parameter is populated with the decls of the various overloads. +bool Sema::isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy, + UnresolvedSetImpl &NonTemplateOverloads) { + ZeroArgCallReturnTy = QualType(); + NonTemplateOverloads.clear(); + if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(&E)) { + for (OverloadExpr::decls_iterator it = Overloads->decls_begin(), + DeclsEnd = Overloads->decls_end(); it != DeclsEnd; ++it) { + // Our overload set may include TemplateDecls, which we'll ignore for our + // present purpose. + if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>(*it)) { + NonTemplateOverloads.addDecl(*it); + if (OverloadDecl->getMinRequiredArguments() == 0) + ZeroArgCallReturnTy = OverloadDecl->getResultType(); + } + } + return true; + } + + if (const DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(&E)) { + if (const FunctionDecl *Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) { + if (Fun->getMinRequiredArguments() == 0) + ZeroArgCallReturnTy = Fun->getResultType(); + return true; + } + } + + // We don't have an expression that's convenient to get a FunctionDecl from, + // but we can at least check if the type is "function of 0 arguments". + QualType ExprTy = E.getType(); + const FunctionType *FunTy = NULL; + QualType PointeeTy = ExprTy->getPointeeType(); + if (!PointeeTy.isNull()) + FunTy = PointeeTy->getAs<FunctionType>(); + if (!FunTy) + FunTy = ExprTy->getAs<FunctionType>(); + if (!FunTy && ExprTy == Context.BoundMemberTy) { + // Look for the bound-member type. If it's still overloaded, give up, + // although we probably should have fallen into the OverloadExpr case above + // if we actually have an overloaded bound member. + QualType BoundMemberTy = Expr::findBoundMemberType(&E); + if (!BoundMemberTy.isNull()) + FunTy = BoundMemberTy->castAs<FunctionType>(); + } + + if (const FunctionProtoType *FPT = + dyn_cast_or_null<FunctionProtoType>(FunTy)) { + if (FPT->getNumArgs() == 0) + ZeroArgCallReturnTy = FunTy->getResultType(); + return true; + } + return false; +} + +/// \brief Give notes for a set of overloads. +/// +/// A companion to isExprCallable. In cases when the name that the programmer +/// wrote was an overloaded function, we may be able to make some guesses about +/// plausible overloads based on their return types; such guesses can be handed +/// off to this method to be emitted as notes. +/// +/// \param Overloads - The overloads to note. +/// \param FinalNoteLoc - If we've suppressed printing some overloads due to +/// -fshow-overloads=best, this is the location to attach to the note about too +/// many candidates. Typically this will be the location of the original +/// ill-formed expression. +void Sema::NoteOverloads(const UnresolvedSetImpl &Overloads, + const SourceLocation FinalNoteLoc) { + int ShownOverloads = 0; + int SuppressedOverloads = 0; + for (UnresolvedSetImpl::iterator It = Overloads.begin(), + DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) { + // FIXME: Magic number for max shown overloads stolen from + // OverloadCandidateSet::NoteCandidates. + if (ShownOverloads >= 4 && + Diags.getShowOverloads() == Diagnostic::Ovl_Best) { + ++SuppressedOverloads; + continue; + } + Diag(cast<FunctionDecl>(*It)->getSourceRange().getBegin(), + diag::note_member_ref_possible_intended_overload); + ++ShownOverloads; + } + if (SuppressedOverloads) + Diag(FinalNoteLoc, diag::note_ovl_too_many_candidates) + << SuppressedOverloads; +} diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 411d424..a26737e 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -146,8 +146,10 @@ struct AccessTarget : public AccessedEntity { MemberNonce _, CXXRecordDecl *NamingClass, DeclAccessPair FoundDecl, - QualType BaseObjectType) - : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType) { + QualType BaseObjectType, + bool IsUsingDecl = false) + : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType), + IsUsingDeclaration(IsUsingDecl) { initialize(); } @@ -216,6 +218,7 @@ private: DeclaringClass = DeclaringClass->getCanonicalDecl(); } + bool IsUsingDeclaration : 1; bool HasInstanceContext : 1; mutable bool CalculatedInstanceContext : 1; mutable const CXXRecordDecl *InstanceContext; @@ -445,8 +448,8 @@ static AccessResult MatchesFriend(Sema &S, continue; // If the template names don't match, it can't be a dependent - // match. This isn't true in C++0x because of template aliases. - if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName()) + // match. + if (CTD->getDeclName() != Friend->getDeclName()) continue; // If the class's context can't instantiate to the friend's @@ -1129,6 +1132,44 @@ static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, DiagnoseAccessPath(S, EC, Entity); } +/// MSVC has a bug where if during an using declaration name lookup, +/// the declaration found is unaccessible (private) and that declaration +/// was bring into scope via another using declaration whose target +/// declaration is accessible (public) then no error is generated. +/// Example: +/// class A { +/// public: +/// int f(); +/// }; +/// class B : public A { +/// private: +/// using A::f; +/// }; +/// class C : public B { +/// private: +/// using B::f; +/// }; +/// +/// Here, B::f is private so this should fail in Standard C++, but +/// because B::f refers to A::f which is public MSVC accepts it. +static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S, + SourceLocation AccessLoc, + AccessTarget &Entity) { + if (UsingShadowDecl *Shadow = + dyn_cast<UsingShadowDecl>(Entity.getTargetDecl())) { + const NamedDecl *OrigDecl = Entity.getTargetDecl()->getUnderlyingDecl(); + if (Entity.getTargetDecl()->getAccess() == AS_private && + (OrigDecl->getAccess() == AS_public || + OrigDecl->getAccess() == AS_protected)) { + S.Diag(AccessLoc, diag::war_ms_using_declaration_inaccessible) + << Shadow->getUsingDecl()->getQualifiedNameAsString() + << OrigDecl->getQualifiedNameAsString(); + return true; + } + } + return false; +} + /// Determines whether the accessed entity is accessible. Public members /// have been weeded out by this point. static AccessResult IsAccessible(Sema &S, @@ -1232,6 +1273,10 @@ static AccessResult CheckEffectiveAccess(Sema &S, AccessTarget &Entity) { assert(Entity.getAccess() != AS_public && "called for public access!"); + if (S.getLangOptions().Microsoft && + IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity)) + return AR_accessible; + switch (IsAccessible(S, EC, Entity)) { case AR_dependent: DelayDependentAccess(S, EC, Loc, Entity); @@ -1415,30 +1460,48 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass, DeclAccessPair::make(Constructor, Access), QualType()); + PartialDiagnostic PD(PDiag()); switch (Entity.getKind()) { default: - AccessEntity.setDiag(IsCopyBindingRefToTemp - ? diag::ext_rvalue_to_reference_access_ctor - : diag::err_access_ctor); + PD = PDiag(IsCopyBindingRefToTemp + ? diag::ext_rvalue_to_reference_access_ctor + : diag::err_access_ctor); + break; case InitializedEntity::EK_Base: - AccessEntity.setDiag(PDiag(diag::err_access_base) - << Entity.isInheritedVirtualBase() - << Entity.getBaseSpecifier()->getType() - << getSpecialMember(Constructor)); + PD = PDiag(diag::err_access_base_ctor); + PD << Entity.isInheritedVirtualBase() + << Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor); break; case InitializedEntity::EK_Member: { const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl()); - AccessEntity.setDiag(PDiag(diag::err_access_field) - << Field->getType() - << getSpecialMember(Constructor)); + PD = PDiag(diag::err_access_field_ctor); + PD << Field->getType() << getSpecialMember(Constructor); break; } } + return CheckConstructorAccess(UseLoc, Constructor, Access, PD); +} + +/// Checks access to a constructor. +Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, + CXXConstructorDecl *Constructor, + AccessSpecifier Access, + PartialDiagnostic PD) { + if (!getLangOptions().AccessControl || + Access == AS_public) + return AR_accessible; + + CXXRecordDecl *NamingClass = Constructor->getParent(); + AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass, + DeclAccessPair::make(Constructor, Access), + QualType()); + AccessEntity.setDiag(PD); + return CheckAccess(*this, UseLoc, AccessEntity); } @@ -1465,7 +1528,8 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc, Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, SourceRange PlacementRange, CXXRecordDecl *NamingClass, - DeclAccessPair Found) { + DeclAccessPair Found, + bool Diagnose) { if (!getLangOptions().AccessControl || !NamingClass || Found.getAccess() == AS_public) @@ -1473,8 +1537,9 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, QualType()); - Entity.setDiag(diag::err_access) - << PlacementRange; + if (Diagnose) + Entity.setDiag(diag::err_access) + << PlacementRange; return CheckAccess(*this, OpLoc, Entity); } @@ -1573,9 +1638,8 @@ void Sema::CheckLookupAccess(const LookupResult &R) { if (I.getAccess() != AS_public) { AccessTarget Entity(Context, AccessedEntity::Member, R.getNamingClass(), I.getPair(), - R.getBaseObjectType()); + R.getBaseObjectType(), R.isUsingDeclaration()); Entity.setDiag(diag::err_access); - CheckAccess(*this, R.getNameLoc(), Entity); } } diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index ed54f0f..e46ad5b 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -252,8 +252,7 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, (CT == CT_CStyle || CT == CT_Functional)); InitializationSequence sequence(S, entity, initKind, &src, 1); - assert(sequence.getKind() == InitializationSequence::FailedSequence && - "initialization succeeded on second try?"); + assert(sequence.Failed() && "initialization succeeded on second try?"); switch (sequence.getFailureKind()) { default: return false; @@ -1195,8 +1194,7 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, // On the other hand, if we're checking a C-style cast, we've still got // the reinterpret_cast way. - if (InitSeq.getKind() == InitializationSequence::FailedSequence && - (CStyle || !DestType->isReferenceType())) + if (InitSeq.Failed() && (CStyle || !DestType->isReferenceType())) return TC_NotApplicable; ExprResult Result @@ -1288,6 +1286,62 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, return TC_Success; } +// Checks for undefined behavior in reinterpret_cast. +// The cases that is checked for is: +// *reinterpret_cast<T*>(&a) +// reinterpret_cast<T&>(a) +// where accessing 'a' as type 'T' will result in undefined behavior. +void Sema::CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType, + bool IsDereference, + SourceRange Range) { + unsigned DiagID = IsDereference ? + diag::warn_pointer_indirection_from_incompatible_type : + diag::warn_undefined_reinterpret_cast; + + if (Diags.getDiagnosticLevel(DiagID, Range.getBegin()) == + Diagnostic::Ignored) { + return; + } + + QualType SrcTy, DestTy; + if (IsDereference) { + if (!SrcType->getAs<PointerType>() || !DestType->getAs<PointerType>()) { + return; + } + SrcTy = SrcType->getPointeeType(); + DestTy = DestType->getPointeeType(); + } else { + if (!DestType->getAs<ReferenceType>()) { + return; + } + SrcTy = SrcType; + DestTy = DestType->getPointeeType(); + } + + // Cast is compatible if the types are the same. + if (Context.hasSameUnqualifiedType(DestTy, SrcTy)) { + return; + } + // or one of the types is a char or void type + if (DestTy->isAnyCharacterType() || DestTy->isVoidType() || + SrcTy->isAnyCharacterType() || SrcTy->isVoidType()) { + return; + } + // or one of the types is a tag type. + if (SrcTy->getAs<TagType>() || DestTy->getAs<TagType>()) { + return; + } + + // FIXME: Scoped enums? + if ((SrcTy->isUnsignedIntegerType() && DestTy->isSignedIntegerType()) || + (SrcTy->isSignedIntegerType() && DestTy->isUnsignedIntegerType())) { + if (Context.getTypeSize(DestTy) == Context.getTypeSize(SrcTy)) { + return; + } + } + + Diag(Range.getBegin(), DiagID) << SrcType << DestType << Range; +} static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, @@ -1324,6 +1378,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return TC_NotApplicable; } + if (!CStyle) { + Self.CheckCompatibleReinterpretCast(SrcType, DestType, + /*isDereference=*/false, OpRange); + } + // C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the // same effect as the conversion *reinterpret_cast<T*>(&x) with the // built-in & and * operators. @@ -1454,9 +1513,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, if (DestType->isIntegralType(Self.Context)) { assert(srcIsPtr && "One type must be a pointer"); // C++ 5.2.10p4: A pointer can be explicitly converted to any integral - // type large enough to hold it. - if (Self.Context.getTypeSize(SrcType) > - Self.Context.getTypeSize(DestType)) { + // type large enough to hold it; except in Microsoft mode, where the + // integral type size doesn't matter. + if ((Self.Context.getTypeSize(SrcType) > + Self.Context.getTypeSize(DestType)) && + !Self.getLangOptions().Microsoft) { msg = diag::err_bad_reinterpret_cast_small_int; return TC_Failed; } diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 7049f6b..61d9e93 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -94,9 +94,13 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, if (EnteringContext) { const Type *NNSType = NNS->getAsType(); if (!NNSType) { - // do nothing, fall out - } else if (const TemplateSpecializationType *SpecType - = NNSType->getAs<TemplateSpecializationType>()) { + return 0; + } + + // Look through type alias templates, per C++0x [temp.dep.type]p1. + NNSType = Context.getCanonicalType(NNSType); + if (const TemplateSpecializationType *SpecType + = NNSType->getAs<TemplateSpecializationType>()) { // We are entering the context of the nested name specifier, so try to // match the nested name specifier to either a primary class template // or a class template partial specialization. @@ -382,7 +386,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, isDependent = ObjectType->isDependentType(); } else if (SS.isSet()) { // This nested-name-specifier occurs after another nested-name-specifier, - // so long into the context associated with the prior nested-name-specifier. + // so look into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, EnteringContext); isDependent = isDependentScopeSpecifier(SS); Found.setContextRange(SS.getRange()); @@ -419,7 +423,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, // class-name or namespace-name. [...] // // Qualified name lookup into a class will not find a namespace-name, - // so we do not need to diagnoste that case specifically. However, + // so we do not need to diagnose that case specifically. However, // this qualified name lookup may find nothing. In that case, perform // unqualified name lookup in the given scope (if available) or // reconstruct the result from when name lookup was performed at template @@ -546,25 +550,33 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, InjectedClassNameTypeLoc InjectedTL = TLB.push<InjectedClassNameTypeLoc>(T); InjectedTL.setNameLoc(IdentifierLoc); - } else if (isa<RecordDecl>(SD)) { + } else if (isa<RecordType>(T)) { RecordTypeLoc RecordTL = TLB.push<RecordTypeLoc>(T); RecordTL.setNameLoc(IdentifierLoc); - } else if (isa<TypedefNameDecl>(SD)) { + } else if (isa<TypedefType>(T)) { TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(T); TypedefTL.setNameLoc(IdentifierLoc); - } else if (isa<EnumDecl>(SD)) { + } else if (isa<EnumType>(T)) { EnumTypeLoc EnumTL = TLB.push<EnumTypeLoc>(T); EnumTL.setNameLoc(IdentifierLoc); - } else if (isa<TemplateTypeParmDecl>(SD)) { + } else if (isa<TemplateTypeParmType>(T)) { TemplateTypeParmTypeLoc TemplateTypeTL = TLB.push<TemplateTypeParmTypeLoc>(T); TemplateTypeTL.setNameLoc(IdentifierLoc); - } else { - assert(isa<UnresolvedUsingTypenameDecl>(SD) && - "Unhandled TypeDecl node in nested-name-specifier"); + } else if (isa<UnresolvedUsingType>(T)) { UnresolvedUsingTypeLoc UnresolvedTL = TLB.push<UnresolvedUsingTypeLoc>(T); UnresolvedTL.setNameLoc(IdentifierLoc); + } else if (isa<SubstTemplateTypeParmType>(T)) { + SubstTemplateTypeParmTypeLoc TL + = TLB.push<SubstTemplateTypeParmTypeLoc>(T); + TL.setNameLoc(IdentifierLoc); + } else if (isa<SubstTemplateTypeParmPackType>(T)) { + SubstTemplateTypeParmPackTypeLoc TL + = TLB.push<SubstTemplateTypeParmPackTypeLoc>(T); + TL.setNameLoc(IdentifierLoc); + } else { + llvm_unreachable("Unhandled TypeDecl node in nested-name-specifier"); } SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T), @@ -704,8 +716,13 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, if (T.isNull()) return true; - // FIXME: Template aliases will need to check the resulting type to make - // sure that it's either dependent or a tag type. + // Alias template specializations can produce types which are not valid + // nested name specifiers. + if (!T->isDependentType() && !T->getAs<TagType>()) { + Diag(TemplateNameLoc, diag::err_nested_name_spec_non_tag) << T; + NoteAllFoundTemplates(Template.get()); + return true; + } // Provide source-location information for the template specialization // type. diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index dcfb7cc..05c257a 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -318,9 +318,13 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { TheCall->getCallee()->getLocStart()); } - // Memset handling - if (FnInfo->isStr("memset")) - CheckMemsetArguments(TheCall); + // Memset/memcpy/memmove handling + if (FDecl->getLinkage() == ExternalLinkage && + (!getLangOptions().CPlusPlus || FDecl->isExternC())) { + if (FnInfo->isStr("memset") || FnInfo->isStr("memcpy") || + FnInfo->isStr("memmove")) + CheckMemsetcpymoveArguments(TheCall, FnInfo); + } return false; } @@ -1797,49 +1801,59 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, //===--- CHECK: Standard memory functions ---------------------------------===// +/// \brief Determine whether the given type is a dynamic class type (e.g., +/// whether it has a vtable). +static bool isDynamicClassType(QualType T) { + if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) + if (CXXRecordDecl *Definition = Record->getDefinition()) + if (Definition->isDynamicClass()) + return true; + + return false; +} + /// \brief Check for dangerous or invalid arguments to memset(). /// -/// This issues warnings on known problematic or dangerous or unspecified -/// arguments to the standard 'memset' function call. +/// This issues warnings on known problematic, dangerous or unspecified +/// arguments to the standard 'memset', 'memcpy', and 'memmove' function calls. /// /// \param Call The call expression to diagnose. -void Sema::CheckMemsetArguments(const CallExpr *Call) { +void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call, + const IdentifierInfo *FnName) { // It is possible to have a non-standard definition of memset. Validate // we have the proper number of arguments, and if not, abort further // checking. if (Call->getNumArgs() != 3) return; - const Expr *Dest = Call->getArg(0)->IgnoreParenImpCasts(); - - // The type checking for this warning is moderately expensive, only do it - // when enabled. - if (getDiagnostics().getDiagnosticLevel(diag::warn_non_pod_memset, - Dest->getExprLoc()) == - Diagnostic::Ignored) - return; - - QualType DestTy = Dest->getType(); - if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) { - QualType PointeeTy = DestPtrTy->getPointeeType(); - if (PointeeTy->isVoidType()) - return; - - // Check the C++11 POD definition regardless of language mode; it is more - // relaxed than earlier definitions and we don't want spurrious warnings. - if (PointeeTy->isCXX11PODType()) - return; - - DiagRuntimeBehavior( - Dest->getExprLoc(), Dest, - PDiag(diag::warn_non_pod_memset) - << PointeeTy << Call->getCallee()->getSourceRange()); + unsigned LastArg = FnName->isStr("memset")? 1 : 2; + for (unsigned ArgIdx = 0; ArgIdx != LastArg; ++ArgIdx) { + const Expr *Dest = Call->getArg(ArgIdx)->IgnoreParenImpCasts(); + + QualType DestTy = Dest->getType(); + if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) { + QualType PointeeTy = DestPtrTy->getPointeeType(); + if (PointeeTy->isVoidType()) + continue; + + // Always complain about dynamic classes. + if (isDynamicClassType(PointeeTy)) { + DiagRuntimeBehavior( + Dest->getExprLoc(), Dest, + PDiag(diag::warn_dyn_class_memaccess) + << ArgIdx << FnName << PointeeTy + << Call->getCallee()->getSourceRange()); + } else { + continue; + } - SourceRange ArgRange = Call->getArg(0)->getSourceRange(); - DiagRuntimeBehavior( - Dest->getExprLoc(), Dest, - PDiag(diag::note_non_pod_memset_silence) - << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)")); + SourceRange ArgRange = Call->getArg(0)->getSourceRange(); + DiagRuntimeBehavior( + Dest->getExprLoc(), Dest, + PDiag(diag::note_bad_memaccess_silence) + << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)")); + break; + } } } @@ -2356,7 +2370,7 @@ IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, // the sign right on this one case. It would be nice if APValue // preserved this. assert(result.isLValue()); - return IntRange(MaxWidth, Ty->isUnsignedIntegerType()); + return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType()); } /// Pseudo-evaluate the given integer expression, estimating the @@ -2530,7 +2544,8 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { llvm::APSInt BitWidthAP = BitField->getBitWidth()->EvaluateAsInt(C); unsigned BitWidth = BitWidthAP.getZExtValue(); - return IntRange(BitWidth, BitField->getType()->isUnsignedIntegerType()); + return IntRange(BitWidth, + BitField->getType()->isUnsignedIntegerOrEnumerationType()); } return IntRange::forValueOfType(C, E->getType()); @@ -2947,6 +2962,13 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (!Source->isIntegerType() || !Target->isIntegerType()) return; + if ((E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull) + == Expr::NPCK_GNUNull) && Target->isIntegerType()) { + S.Diag(E->getExprLoc(), diag::warn_impcast_null_pointer_to_integer) + << E->getSourceRange() << clang::SourceRange(CC); + return; + } + IntRange SourceRange = GetExprRange(S.Context, E); IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target); diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index cc8726d..e328eeb 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -2658,6 +2658,16 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) { case Decl::UnresolvedUsingTypename: return CXCursor_UsingDeclaration; + case Decl::ObjCPropertyImpl: + switch (cast<ObjCPropertyImplDecl>(D)->getPropertyImplementation()) { + case ObjCPropertyImplDecl::Dynamic: + return CXCursor_ObjCDynamicDecl; + + case ObjCPropertyImplDecl::Synthesize: + return CXCursor_ObjCSynthesizeDecl; + } + break; + default: if (TagDecl *TD = dyn_cast<TagDecl>(D)) { switch (TD->getTagKind()) { @@ -3078,6 +3088,7 @@ typedef llvm::SmallPtrSet<IdentifierInfo*, 16> AddedPropertiesSet; static void AddObjCProperties(ObjCContainerDecl *Container, bool AllowCategories, + bool AllowNullaryMethods, DeclContext *CurContext, AddedPropertiesSet &AddedProperties, ResultBuilder &Results) { @@ -3092,32 +3103,75 @@ static void AddObjCProperties(ObjCContainerDecl *Container, Results.MaybeAddResult(Result(*P, 0), CurContext); } + // Add nullary methods + if (AllowNullaryMethods) { + ASTContext &Context = Container->getASTContext(); + for (ObjCContainerDecl::method_iterator M = Container->meth_begin(), + MEnd = Container->meth_end(); + M != MEnd; ++M) { + if (M->getSelector().isUnarySelector()) + if (IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0)) + if (AddedProperties.insert(Name)) { + CodeCompletionBuilder Builder(Results.getAllocator()); + AddResultTypeChunk(Context, *M, Builder); + Builder.AddTypedTextChunk( + Results.getAllocator().CopyString(Name->getName())); + + CXAvailabilityKind Availability = CXAvailability_Available; + switch (M->getAvailability()) { + case AR_Available: + case AR_NotYetIntroduced: + Availability = CXAvailability_Available; + break; + + case AR_Deprecated: + Availability = CXAvailability_Deprecated; + break; + + case AR_Unavailable: + Availability = CXAvailability_NotAvailable; + break; + } + + Results.MaybeAddResult(Result(Builder.TakeString(), + CCP_MemberDeclaration + CCD_MethodAsProperty, + M->isInstanceMethod() + ? CXCursor_ObjCInstanceMethodDecl + : CXCursor_ObjCClassMethodDecl, + Availability), + CurContext); + } + } + } + + // Add properties in referenced protocols. if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) { for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(), PEnd = Protocol->protocol_end(); P != PEnd; ++P) - AddObjCProperties(*P, AllowCategories, CurContext, AddedProperties, - Results); + AddObjCProperties(*P, AllowCategories, AllowNullaryMethods, CurContext, + AddedProperties, Results); } else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){ if (AllowCategories) { // Look through categories. for (ObjCCategoryDecl *Category = IFace->getCategoryList(); Category; Category = Category->getNextClassCategory()) - AddObjCProperties(Category, AllowCategories, CurContext, - AddedProperties, Results); + AddObjCProperties(Category, AllowCategories, AllowNullaryMethods, + CurContext, AddedProperties, Results); } // Look through protocols. for (ObjCInterfaceDecl::all_protocol_iterator I = IFace->all_referenced_protocol_begin(), E = IFace->all_referenced_protocol_end(); I != E; ++I) - AddObjCProperties(*I, AllowCategories, CurContext, AddedProperties, - Results); + AddObjCProperties(*I, AllowCategories, AllowNullaryMethods, CurContext, + AddedProperties, Results); // Look in the superclass. if (IFace->getSuperClass()) - AddObjCProperties(IFace->getSuperClass(), AllowCategories, CurContext, + AddObjCProperties(IFace->getSuperClass(), AllowCategories, + AllowNullaryMethods, CurContext, AddedProperties, Results); } else if (const ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) { @@ -3125,8 +3179,8 @@ static void AddObjCProperties(ObjCContainerDecl *Container, for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(), PEnd = Category->protocol_end(); P != PEnd; ++P) - AddObjCProperties(*P, AllowCategories, CurContext, AddedProperties, - Results); + AddObjCProperties(*P, AllowCategories, AllowNullaryMethods, CurContext, + AddedProperties, Results); } } @@ -3192,14 +3246,16 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, const ObjCObjectPointerType *ObjCPtr = BaseType->getAsObjCInterfacePointerType(); assert(ObjCPtr && "Non-NULL pointer guaranteed above!"); - AddObjCProperties(ObjCPtr->getInterfaceDecl(), true, CurContext, + AddObjCProperties(ObjCPtr->getInterfaceDecl(), true, + /*AllowNullaryMethods=*/true, CurContext, AddedProperties, Results); // Add properties from the protocols in a qualified interface. for (ObjCObjectPointerType::qual_iterator I = ObjCPtr->qual_begin(), E = ObjCPtr->qual_end(); I != E; ++I) - AddObjCProperties(*I, true, CurContext, AddedProperties, Results); + AddObjCProperties(*I, true, /*AllowNullaryMethods=*/true, CurContext, + AddedProperties, Results); } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || (!IsArrow && BaseType->isObjCObjectType())) { // Objective-C instance variable access. @@ -4109,6 +4165,8 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { Results.AddResult(CodeCompletionResult("copy")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic)) Results.AddResult(CodeCompletionResult("nonatomic")); + if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_atomic)) + Results.AddResult(CodeCompletionResult("atomic")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) { CodeCompletionBuilder Setter(Results.getAllocator()); Setter.AddTypedTextChunk("setter"); @@ -5334,11 +5392,13 @@ void Sema::CodeCompleteObjCPropertyDefinition(Scope *S, Decl *ObjCImpDecl) { Results.EnterNewScope(); if (ObjCImplementationDecl *ClassImpl = dyn_cast<ObjCImplementationDecl>(Container)) - AddObjCProperties(ClassImpl->getClassInterface(), false, CurContext, + AddObjCProperties(ClassImpl->getClassInterface(), false, + /*AllowNullaryMethods=*/false, CurContext, AddedProperties, Results); else AddObjCProperties(cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl(), - false, CurContext, AddedProperties, Results); + false, /*AllowNullaryMethods=*/false, CurContext, + AddedProperties, Results); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, @@ -5549,7 +5609,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, bool IsInstanceMethod, QualType ReturnType, ASTContext &Context, - const KnownMethodsMap &KnownMethods, + VisitedSelectorSet &KnownSelectors, ResultBuilder &Results) { IdentifierInfo *PropName = Property->getIdentifier(); if (!PropName || PropName->getLength() == 0) @@ -5595,7 +5655,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // Add the normal accessor -(type)key. if (IsInstanceMethod && - !KnownMethods.count(Selectors.getNullarySelector(PropName)) && + KnownSelectors.insert(Selectors.getNullarySelector(PropName)) && ReturnTypeMatchesProperty && !Property->getGetterMethodDecl()) { if (ReturnType.isNull()) AddObjCPassingTypeChunk(Property->getType(), Context, Builder); @@ -5615,7 +5675,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Property->getType()->isBooleanType())))) { std::string SelectorName = (llvm::Twine("is") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("BOOL"); @@ -5634,7 +5694,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, !Property->getSetterMethodDecl()) { std::string SelectorName = (llvm::Twine("set") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -5685,7 +5745,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, (ReturnType.isNull() || ReturnType->isIntegerType())) { std::string SelectorName = (llvm::Twine("countOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSUInteger"); @@ -5708,7 +5768,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (llvm::Twine("objectIn") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("id"); @@ -5735,7 +5795,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (llvm::Twine(Property->getName()) + "AtIndexes").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSArray *"); @@ -5760,7 +5820,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get("range") }; - if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) { + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -5794,7 +5854,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get(SelectorName) }; - if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) { + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -5826,7 +5886,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get("atIndexes") }; - if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) { + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -5854,7 +5914,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (llvm::Twine("removeObjectFrom") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -5876,7 +5936,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (llvm::Twine("remove") + UpperKey + "AtIndexes").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -5902,7 +5962,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get("withObject") }; - if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) { + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -5935,7 +5995,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get(SelectorName2) }; - if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) { + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -5968,7 +6028,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ->getName() == "NSEnumerator"))) { std::string SelectorName = (llvm::Twine("enumeratorOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSEnumerator *"); @@ -5986,7 +6046,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) { std::string SelectorName = (llvm::Twine("memberOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("object-type"); @@ -6016,7 +6076,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (llvm::Twine("add") + UpperKey + llvm::Twine("Object")).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6038,7 +6098,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (llvm::Twine("add") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6060,7 +6120,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (llvm::Twine("remove") + UpperKey + llvm::Twine("Object")).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6082,7 +6142,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (llvm::Twine("remove") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6103,7 +6163,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (llvm::Twine("intersect") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6131,7 +6191,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (llvm::Twine("keyPathsForValuesAffecting") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSSet *"); @@ -6140,7 +6200,28 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName)); Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, - CXCursor_ObjCInstanceMethodDecl)); + CXCursor_ObjCClassMethodDecl)); + } + } + + // + (BOOL)automaticallyNotifiesObserversForKey + if (!IsInstanceMethod && + (ReturnType.isNull() || + ReturnType->isIntegerType() || + ReturnType->isBooleanType())) { + std::string SelectorName + = (llvm::Twine("automaticallyNotifiesObserversOf") + UpperKey).str(); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { + if (ReturnType.isNull()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddTextChunk("BOOL"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + } + + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName)); + Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, + CXCursor_ObjCClassMethodDecl)); } } } @@ -6271,6 +6352,13 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, llvm::SmallVector<ObjCContainerDecl *, 4> Containers; Containers.push_back(SearchDecl); + VisitedSelectorSet KnownSelectors; + for (KnownMethodsMap::iterator M = KnownMethods.begin(), + MEnd = KnownMethods.end(); + M != MEnd; ++M) + KnownSelectors.insert(M->first); + + ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(SearchDecl); if (!IFace) if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(SearchDecl)) @@ -6287,7 +6375,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, PEnd = Containers[I]->prop_end(); P != PEnd; ++P) { AddObjCKeyValueCompletions(*P, IsInstanceMethod, ReturnType, Context, - KnownMethods, Results); + KnownSelectors, Results); } } } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 7214988..9446c0e 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -891,19 +891,19 @@ static bool isOutOfScopePreviousDeclaration(NamedDecl *, /// Filters out lookup results that don't fall within the given scope /// as determined by isDeclInScope. -static void FilterLookupForScope(Sema &SemaRef, LookupResult &R, - DeclContext *Ctx, Scope *S, - bool ConsiderLinkage, - bool ExplicitInstantiationOrSpecialization) { +void Sema::FilterLookupForScope(LookupResult &R, + DeclContext *Ctx, Scope *S, + bool ConsiderLinkage, + bool ExplicitInstantiationOrSpecialization) { LookupResult::Filter F = R.makeFilter(); while (F.hasNext()) { NamedDecl *D = F.next(); - if (SemaRef.isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization)) + if (isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization)) continue; if (ConsiderLinkage && - isOutOfScopePreviousDeclaration(D, Ctx, SemaRef.Context)) + isOutOfScopePreviousDeclaration(D, Ctx, Context)) continue; F.erase(); @@ -938,7 +938,7 @@ static void RemoveUsingDecls(LookupResult &R) { static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) { // FIXME: Should check for private access too but access is set after we get // the decl here. - if (D->isThisDeclarationADefinition()) + if (D->doesThisDeclarationHaveABody()) return false; if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D)) @@ -973,10 +973,9 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { return false; } - if (FD->isThisDeclarationADefinition() && + if (FD->doesThisDeclarationHaveABody() && Context.DeclMustBeEmitted(FD)) return false; - } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (!VD->isFileVarDecl() || VD->getType().isConstant(Context) || @@ -1506,18 +1505,21 @@ struct GNUCompatibleParamWarning { /// getSpecialMember - get the special member enum for a method. Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) { + if (Ctor->isDefaultConstructor()) + return Sema::CXXDefaultConstructor; + if (Ctor->isCopyConstructor()) return Sema::CXXCopyConstructor; - - return Sema::CXXConstructor; - } - - if (isa<CXXDestructorDecl>(MD)) + + if (Ctor->isMoveConstructor()) + return Sema::CXXMoveConstructor; + } else if (isa<CXXDestructorDecl>(MD)) { return Sema::CXXDestructor; - - assert(MD->isCopyAssignmentOperator() && - "Must have copy assignment operator"); - return Sema::CXXCopyAssignment; + } else if (MD->isCopyAssignmentOperator()) { + return Sema::CXXCopyAssignment; + } + + return Sema::CXXInvalid; } /// canRedefineFunction - checks if a function can be redefined. Currently, @@ -1525,7 +1527,7 @@ Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { /// GNU89 mode. static bool canRedefineFunction(const FunctionDecl *FD, const LangOptions& LangOpts) { - return (LangOpts.GNUMode && !LangOpts.C99 && !LangOpts.CPlusPlus && + return (LangOpts.GNUInline && !LangOpts.CPlusPlus && FD->isInlineSpecified() && FD->getStorageClass() == SC_Extern); } @@ -1728,6 +1730,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { << New << getSpecialMember(OldMethod); return true; } + } else if (OldMethod->isExplicitlyDefaulted()) { + Diag(NewMethod->getLocation(), + diag::err_definition_of_explicitly_defaulted_member) + << getSpecialMember(OldMethod); + return true; } } @@ -1907,10 +1914,6 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { if (Old->isPure()) New->setPure(); - // Merge the "deleted" flag. - if (Old->isDeleted()) - New->setDeleted(); - // Merge attributes from the parameters. These can mismatch with K&R // declarations. if (New->getNumParams() == Old->getNumParams()) @@ -1933,7 +1936,9 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, for (ObjCMethodDecl::param_iterator oi = oldMethod->param_begin(), ni = newMethod->param_begin(), ne = newMethod->param_end(); ni != ne; ++ni, ++oi) - mergeParamDeclAttributes(*ni, *oi, Context); + mergeParamDeclAttributes(*ni, *oi, Context); + + CheckObjCMethodOverride(newMethod, oldMethod, true); } /// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and @@ -2132,6 +2137,16 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { /// no declarator (e.g. "struct foo;") is parsed. Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS) { + return ParsedFreeStandingDeclSpec(S, AS, DS, + MultiTemplateParamsArg(*this, 0, 0)); +} + +/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with +/// no declarator (e.g. "struct foo;") is parsed. It also accopts template +/// parameters to cope with template friend declarations. +Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS, + MultiTemplateParamsArg TemplateParams) { Decl *TagD = 0; TagDecl *Tag = 0; if (DS.getTypeSpecType() == DeclSpec::TST_class || @@ -2163,7 +2178,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, // whatever routines created it handled the friendship aspect. if (TagD && !Tag) return 0; - return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0)); + return ActOnFriendTypeDecl(S, DS, TemplateParams); } // Track whether we warned about the fact that there aren't any @@ -2484,6 +2499,24 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, PrevSpec, DiagID, getLangOptions()); } + // Ignore const/volatile/restrict qualifiers. + if (DS.getTypeQualifiers()) { + if (DS.getTypeQualifiers() & DeclSpec::TQ_const) + Diag(DS.getConstSpecLoc(), diag::ext_anonymous_struct_union_qualified) + << Record->isUnion() << 0 + << FixItHint::CreateRemoval(DS.getConstSpecLoc()); + if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) + Diag(DS.getVolatileSpecLoc(), diag::ext_anonymous_struct_union_qualified) + << Record->isUnion() << 1 + << FixItHint::CreateRemoval(DS.getVolatileSpecLoc()); + if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) + Diag(DS.getRestrictSpecLoc(), diag::ext_anonymous_struct_union_qualified) + << Record->isUnion() << 2 + << FixItHint::CreateRemoval(DS.getRestrictSpecLoc()); + + DS.ClearTypeQualifiers(); + } + // C++ [class.union]p2: // The member-specification of an anonymous union shall only // define non-static data members. [Note: nested types and @@ -2502,7 +2535,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Invalid = true; } - if (CheckNontrivialField(FD)) + // C++ [class.union]p1 + // An object of a class with a non-trivial constructor, a non-trivial + // copy constructor, a non-trivial destructor, or a non-trivial copy + // assignment operator cannot be a member of a union, nor can an + // array of such objects. + if (!getLangOptions().CPlusPlus0x && CheckNontrivialField(FD)) Invalid = true; } else if ((*Mem)->isImplicit()) { // Any implicit members are fine. @@ -2572,7 +2610,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), TInfo, - /*BitWidth=*/0, /*Mutable=*/false); + /*BitWidth=*/0, /*Mutable=*/false, + /*HasInit=*/false); Anon->setAccess(AS); if (getLangOptions().CPlusPlus) FieldCollector->Add(cast<FieldDecl>(Anon)); @@ -2662,7 +2701,8 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), TInfo, - /*BitWidth=*/0, /*Mutable=*/false); + /*BitWidth=*/0, /*Mutable=*/false, + /*HasInit=*/false); Anon->setImplicit(); // Add the anonymous struct object to the current context. @@ -2829,7 +2869,8 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, switch (DS.getTypeSpecType()) { case DeclSpec::TST_typename: case DeclSpec::TST_typeofType: - case DeclSpec::TST_decltype: { + case DeclSpec::TST_decltype: + case DeclSpec::TST_underlyingType: { // Grab the type from the parser. TypeSourceInfo *TSI = 0; QualType T = S.GetTypeFromParser(DS.getRepAsType(), &TSI); @@ -2883,8 +2924,10 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, return false; } -Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { - return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false); +Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D, + bool IsFunctionDefinition) { + return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), + IsFunctionDefinition); } /// DiagnoseClassNameShadow - Implement C++ [class.mem]p13: @@ -2952,7 +2995,6 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, << D.getCXXScopeSpec().getRange(); return 0; } - bool IsDependentContext = DC->isDependentContext(); if (!IsDependentContext && @@ -3294,15 +3336,13 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewTD, D); + CheckTypedefForVariablyModifiedType(S, NewTD); + return ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration); } -/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which -/// declares a typedef-name, either using the 'typedef' type specifier or via -/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'. -NamedDecl* -Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, - LookupResult &Previous, bool &Redeclaration) { +void +Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) { // C99 6.7.7p2: If a typedef name specifies a variably modified type // then it shall have block scope. // Note that variably modified types must be fixed before merging the decl so @@ -3333,10 +3373,18 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, } } } +} + +/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which +/// declares a typedef-name, either using the 'typedef' type specifier or via +/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'. +NamedDecl* +Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, + LookupResult &Previous, bool &Redeclaration) { // Merge the decl with the existing one if appropriate. If the decl is // in an outer scope, it isn't the same thing. - FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false, + FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/ false, /*ExplicitInstantiationOrSpecialization=*/false); if (!Previous.empty()) { Redeclaration = true; @@ -3518,7 +3566,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, bool Invalid = false; if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( - D.getDeclSpec().getSourceRange().getBegin(), + D.getDeclSpec().getSourceRange().getBegin(), + D.getIdentifierLoc(), D.getCXXScopeSpec(), TemplateParamLists.get(), TemplateParamLists.size(), @@ -3540,7 +3589,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, << II << SourceRange(TemplateParams->getTemplateLoc(), TemplateParams->getRAngleLoc()); - isExplicitSpecialization = true; } } @@ -3615,7 +3663,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Don't consider existing declarations that are in a different // scope and are out-of-semantic-context declarations (if the new // declaration has linkage). - FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage(), + FilterLookupForScope(Previous, DC, S, NewVD->hasLinkage(), isExplicitSpecialization); if (!getLangOptions().CPlusPlus) @@ -3806,8 +3854,12 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, } if (NewVD->hasLocalStorage() && T.isObjCGCWeak() - && !NewVD->hasAttr<BlocksAttr>()) - Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local); + && !NewVD->hasAttr<BlocksAttr>()) { + if (getLangOptions().getGCMode() != LangOptions::NonGC) + Diag(NewVD->getLocation(), diag::warn_gc_attribute_weak_on_local); + else + Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local); + } bool isVM = T->isVariablyModifiedType(); if (isVM || NewVD->hasAttr<CleanupAttr>() || @@ -4062,7 +4114,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Set the lexical context. NewFD->setLexicalDeclContext(CurContext); // Filter out previous declarations that don't match the scope. - FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(), + FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), /*ExplicitInstantiationOrSpecialization=*/false); } else { isFriend = D.getDeclSpec().isFriendSpecified(); @@ -4088,24 +4140,38 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, R = CheckConstructorDeclarator(D, R, SC); // Create the new declaration - NewFD = CXXConstructorDecl::Create(Context, + CXXConstructorDecl *NewCD = CXXConstructorDecl::Create( + Context, cast<CXXRecordDecl>(DC), D.getSourceRange().getBegin(), NameInfo, R, TInfo, isExplicit, isInline, /*isImplicitlyDeclared=*/false); + + NewFD = NewCD; } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { // This is a C++ destructor declaration. if (DC->isRecord()) { R = CheckDestructorDeclarator(D, R, SC); + CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); - NewFD = CXXDestructorDecl::Create(Context, - cast<CXXRecordDecl>(DC), + CXXDestructorDecl *NewDD = CXXDestructorDecl::Create(Context, Record, D.getSourceRange().getBegin(), NameInfo, R, TInfo, isInline, /*isImplicitlyDeclared=*/false); + NewFD = NewDD; isVirtualOkay = true; + + // If the class is complete, then we now create the implicit exception + // specification. If the class is incomplete or dependent, we can't do + // it yet. + if (getLangOptions().CPlusPlus0x && !Record->isDependentType() && + Record->getDefinition() && !Record->isBeingDefined() && + R->getAs<FunctionProtoType>()->getExceptionSpecType() == EST_None) { + AdjustDestructorExceptionSpec(Record, NewDD); + } + } else { Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); @@ -4162,11 +4228,13 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, isStatic = true; // This is a C++ method declaration. - NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC), - D.getSourceRange().getBegin(), - NameInfo, R, TInfo, - isStatic, SCAsWritten, isInline, - SourceLocation()); + CXXMethodDecl *NewMD = CXXMethodDecl::Create( + Context, cast<CXXRecordDecl>(DC), + D.getSourceRange().getBegin(), + NameInfo, R, TInfo, + isStatic, SCAsWritten, isInline, + SourceLocation()); + NewFD = NewMD; isVirtualOkay = !isStatic; } else { @@ -4202,6 +4270,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( D.getDeclSpec().getSourceRange().getBegin(), + D.getIdentifierLoc(), D.getCXXScopeSpec(), TemplateParamLists.get(), TemplateParamLists.size(), @@ -4339,7 +4408,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } // Filter out previous declarations that don't match the scope. - FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(), + FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), isExplicitSpecialization || isFunctionTemplateSpecialization); @@ -4406,6 +4475,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, bool IsTypeAlias = false; if (const TypedefType *TT = Param->getType()->getAs<TypedefType>()) IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl()); + else if (const TemplateSpecializationType *TST = + Param->getType()->getAs<TemplateSpecializationType>()) + IsTypeAlias = TST->isTypeAlias(); Diag(Param->getLocation(), diag::err_param_typedef_of_void) << IsTypeAlias; } @@ -4452,8 +4524,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (!getLangOptions().CPlusPlus) { // Perform semantic checking on the function declaration. - bool isExplctSpecialization=false; - CheckFunctionDeclaration(S, NewFD, Previous, isExplctSpecialization, + bool isExplicitSpecialization=false; + CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, Redeclaration); assert((NewFD->isInvalidDecl() || !Redeclaration || Previous.getResultKind() != LookupResult::FoundOverloaded) && @@ -4476,7 +4548,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, HasExplicitTemplateArgs = true; - if (FunctionTemplate) { + if (NewFD->isInvalidDecl()) { + HasExplicitTemplateArgs = false; + } else if (FunctionTemplate) { // Function template with explicit template arguments. Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec) << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc); @@ -4532,6 +4606,16 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, (HasExplicitTemplateArgs ? &TemplateArgs : 0), Previous)) NewFD->setInvalidDecl(); + + // C++ [dcl.stc]p1: + // A storage-class-specifier shall not be specified in an explicit + // specialization (14.7.3) + if (SC != SC_None) { + Diag(NewFD->getLocation(), + diag::err_explicit_specialization_storage_class) + << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); + } + } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) { if (CheckMemberSpecialization(NewFD, Previous)) NewFD->setInvalidDecl(); @@ -4647,8 +4731,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, << D.getCXXScopeSpec().getRange(); } } - - + + // Handle attributes. We need to have merged decls when handling attributes // (for example to check for conflicts, etc). // FIXME: This needs to happen before we merge declarations. Then, @@ -4661,7 +4745,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (Redeclaration && Previous.isSingleResult()) { const FunctionDecl *Def; FunctionDecl *PrevFD = dyn_cast<FunctionDecl>(Previous.getFoundDecl()); - if (PrevFD && PrevFD->hasBody(Def) && D.hasAttributes()) { + if (PrevFD && PrevFD->isDefined(Def) && D.hasAttributes()) { Diag(NewFD->getLocation(), diag::warn_attribute_precede_definition); Diag(Def->getLocation(), diag::note_previous_definition); } @@ -5076,9 +5160,11 @@ namespace { if (OrigDecl != ReferenceDecl) return; LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName, Sema::NotForRedeclaration); - S.Diag(SubExpr->getLocStart(), diag::warn_uninit_self_reference_in_init) - << Result.getLookupName() << OrigDecl->getLocation() - << SubExpr->getSourceRange(); + S.DiagRuntimeBehavior(SubExpr->getLocStart(), SubExpr, + S.PDiag(diag::warn_uninit_self_reference_in_init) + << Result.getLookupName() + << OrigDecl->getLocation() + << SubExpr->getSourceRange()); } }; } @@ -5553,40 +5639,53 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, return; } - const RecordType *Record - = Context.getBaseElementType(Type)->getAs<RecordType>(); - if (Record && getLangOptions().CPlusPlus && - cast<CXXRecordDecl>(Record->getDecl())->isPOD()) { - // C++03 [dcl.init]p9: - // If no initializer is specified for an object, and the - // object is of (possibly cv-qualified) non-POD class type (or - // array thereof), the object shall be default-initialized; if - // the object is of const-qualified type, the underlying class - // type shall have a user-declared default - // constructor. Otherwise, if no initializer is specified for - // a non- static object, the object and its subobjects, if - // any, have an indeterminate initial value); if the object - // or any of its subobjects are of const-qualified type, the - // program is ill-formed. - } else { - // Check for jumps past the implicit initializer. C++0x - // clarifies that this applies to a "variable with automatic - // storage duration", not a "local variable". - if (getLangOptions().CPlusPlus && Var->hasLocalStorage()) - getCurFunction()->setHasBranchProtectedScope(); - - InitializedEntity Entity = InitializedEntity::InitializeVariable(Var); - InitializationKind Kind - = InitializationKind::CreateDefault(Var->getLocation()); - - InitializationSequence InitSeq(*this, Entity, Kind, 0, 0); - ExprResult Init = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, 0, 0)); - if (Init.isInvalid()) - Var->setInvalidDecl(); - else if (Init.get()) - Var->setInit(MaybeCreateExprWithCleanups(Init.get())); + // Check for jumps past the implicit initializer. C++0x + // clarifies that this applies to a "variable with automatic + // storage duration", not a "local variable". + // C++0x [stmt.dcl]p3 + // A program that jumps from a point where a variable with automatic + // storage duration is not in scope to a point where it is in scope is + // ill-formed unless the variable has scalar type, class type with a + // trivial default constructor and a trivial destructor, a cv-qualified + // version of one of these types, or an array of one of the preceding + // types and is declared without an initializer. + if (getLangOptions().CPlusPlus && Var->hasLocalStorage()) { + if (const RecordType *Record + = Context.getBaseElementType(Type)->getAs<RecordType>()) { + CXXRecordDecl *CXXRecord = cast<CXXRecordDecl>(Record->getDecl()); + if ((!getLangOptions().CPlusPlus0x && !CXXRecord->isPOD()) || + (getLangOptions().CPlusPlus0x && + (!CXXRecord->hasTrivialDefaultConstructor() || + !CXXRecord->hasTrivialDestructor()))) + getCurFunction()->setHasBranchProtectedScope(); + } } + + // C++03 [dcl.init]p9: + // If no initializer is specified for an object, and the + // object is of (possibly cv-qualified) non-POD class type (or + // array thereof), the object shall be default-initialized; if + // the object is of const-qualified type, the underlying class + // type shall have a user-declared default + // constructor. Otherwise, if no initializer is specified for + // a non- static object, the object and its subobjects, if + // any, have an indeterminate initial value); if the object + // or any of its subobjects are of const-qualified type, the + // program is ill-formed. + // C++0x [dcl.init]p11: + // If no initializer is specified for an object, the object is + // default-initialized; [...]. + InitializedEntity Entity = InitializedEntity::InitializeVariable(Var); + InitializationKind Kind + = InitializationKind::CreateDefault(Var->getLocation()); + + InitializationSequence InitSeq(*this, Entity, Kind, 0, 0); + ExprResult Init = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, 0, 0)); + if (Init.isInvalid()) + Var->setInvalidDecl(); + else if (Init.get()) + Var->setInit(MaybeCreateExprWithCleanups(Init.get())); CheckCompleteVariableDeclaration(Var); } @@ -6056,7 +6155,7 @@ void Sema::CheckForFunctionRedefinition(FunctionDecl *FD) { // Don't complain if we're in GNU89 mode and the previous definition // was an extern inline function. const FunctionDecl *Definition; - if (FD->hasBody(Definition) && + if (FD->isDefined(Definition) && !canRedefineFunction(Definition, getLangOptions())) { if (getLangOptions().GNUMode && Definition->isInlineSpecified() && Definition->getStorageClass() == SC_Extern) @@ -6221,6 +6320,11 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, WP.disableCheckFallThrough(); } + // MSVC permits the use of pure specifier (=0) on function definition, + // defined at class scope, warn about this non standard construct. + if (getLangOptions().Microsoft && FD->isPure()) + Diag(FD->getLocation(), diag::warn_pure_function_definition); + if (!FD->isInvalidDecl()) { DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(), @@ -6499,7 +6603,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, /// /// \returns true if the new tag kind is acceptable, false otherwise. bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, - TagTypeKind NewTag, + TagTypeKind NewTag, bool isDefinition, SourceLocation NewTagLoc, const IdentifierInfo &Name) { // C++ [dcl.type.elab]p3: @@ -6516,8 +6620,9 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, // struct class-key shall be used to refer to a class (clause 9) // declared using the class or struct class-key. TagTypeKind OldTag = Previous->getTagKind(); - if (OldTag == NewTag) - return true; + if (!isDefinition || (NewTag != TTK_Class && NewTag != TTK_Struct)) + if (OldTag == NewTag) + return true; if ((OldTag == TTK_Struct || OldTag == TTK_Class) && (NewTag == TTK_Struct || NewTag == TTK_Class)) { @@ -6526,12 +6631,63 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous)) isTemplate = Record->getDescribedClassTemplate(); + if (!ActiveTemplateInstantiations.empty()) { + // In a template instantiation, do not offer fix-its for tag mismatches + // since they usually mess up the template instead of fixing the problem. + Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) + << (NewTag == TTK_Class) << isTemplate << &Name; + return true; + } + + if (isDefinition) { + // On definitions, check previous tags and issue a fix-it for each + // one that doesn't match the current tag. + if (Previous->getDefinition()) { + // Don't suggest fix-its for redefinitions. + return true; + } + + bool previousMismatch = false; + for (TagDecl::redecl_iterator I(Previous->redecls_begin()), + E(Previous->redecls_end()); I != E; ++I) { + if (I->getTagKind() != NewTag) { + if (!previousMismatch) { + previousMismatch = true; + Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch) + << (NewTag == TTK_Class) << isTemplate << &Name; + } + Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion) + << (NewTag == TTK_Class) + << FixItHint::CreateReplacement(I->getInnerLocStart(), + NewTag == TTK_Class? + "class" : "struct"); + } + } + return true; + } + + // Check for a previous definition. If current tag and definition + // are same type, do nothing. If no definition, but disagree with + // with previous tag type, give a warning, but no fix-it. + const TagDecl *Redecl = Previous->getDefinition() ? + Previous->getDefinition() : Previous; + if (Redecl->getTagKind() == NewTag) { + return true; + } + Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) << (NewTag == TTK_Class) - << isTemplate << &Name - << FixItHint::CreateReplacement(SourceRange(NewTagLoc), - OldTag == TTK_Class? "class" : "struct"); - Diag(Previous->getLocation(), diag::note_previous_use); + << isTemplate << &Name; + Diag(Redecl->getLocation(), diag::note_previous_use); + + // If there is a previous defintion, suggest a fix-it. + if (Previous->getDefinition()) { + Diag(NewTagLoc, diag::note_struct_class_suggestion) + << (Redecl->getTagKind() == TTK_Class) + << FixItHint::CreateReplacement(SourceRange(NewTagLoc), + Redecl->getTagKind() == TTK_Class? "class" : "struct"); + } + return true; } return false; @@ -6567,7 +6723,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (TemplateParameterLists.size() > 0 || (SS.isNotEmpty() && TUK != TUK_Reference)) { if (TemplateParameterList *TemplateParams - = MatchTemplateParametersToScopeSpecifier(KWLoc, SS, + = MatchTemplateParametersToScopeSpecifier(KWLoc, NameLoc, SS, TemplateParameterLists.get(), TemplateParameterLists.size(), TUK == TUK_Friend, @@ -6705,6 +6861,17 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // shouldn't be diagnosing. LookupName(Previous, S); + if (Previous.isAmbiguous() && + (TUK == TUK_Definition || TUK == TUK_Declaration)) { + LookupResult::Filter F = Previous.makeFilter(); + while (F.hasNext()) { + NamedDecl *ND = F.next(); + if (ND->getDeclContext()->getRedeclContext() != SearchDC) + F.erase(); + } + F.done(); + } + // Note: there used to be some attempt at recovery here. if (Previous.isAmbiguous()) return 0; @@ -6846,7 +7013,9 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, isDeclInScope(PrevDecl, SearchDC, S, isExplicitSpecialization)) { // Make sure that this wasn't declared as an enum and now used as a // struct or something similar. - if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) { + if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, + TUK == TUK_Definition, KWLoc, + *Name)) { bool SafeToContinue = (PrevTagDecl->getTagKind() != TTK_Enum && Kind != TTK_Enum); @@ -6911,8 +7080,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // for the consumer of this Decl to know it doesn't own it. // For our current ASTs this shouldn't be a problem, but will // need to be changed with DeclGroups. - if ((TUK == TUK_Reference && !PrevTagDecl->getFriendObjectKind()) || - TUK == TUK_Friend) + if ((TUK == TUK_Reference && (!PrevTagDecl->getFriendObjectKind() || + getLangOptions().Microsoft)) || TUK == TUK_Friend) return PrevTagDecl; // Diagnose attempts to redefine a tag. @@ -7154,8 +7323,12 @@ CreateNewDecl: New->setLexicalDeclContext(CurContext); // Mark this as a friend decl if applicable. + // In Microsoft mode, a friend declaration also acts as a forward + // declaration so we always pass true to setObjectOfFriendDecl to make + // the tag name visible. if (TUK == TUK_Friend) - New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty()); + New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty() || + getLangOptions().Microsoft); // Set the access specifier. if (!Invalid && SearchDC->isRecord()) @@ -7341,14 +7514,13 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, return false; } -/// ActOnField - Each field of a struct/union/class is passed into this in order +/// ActOnField - Each field of a C struct/union is passed into this in order /// to create a FieldDecl object for it. -Decl *Sema::ActOnField(Scope *S, Decl *TagD, - SourceLocation DeclStart, - Declarator &D, ExprTy *BitfieldWidth) { +Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, + Declarator &D, ExprTy *BitfieldWidth) { FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD), DeclStart, D, static_cast<Expr*>(BitfieldWidth), - AS_public); + /*HasInit=*/false, AS_public); return Res; } @@ -7356,7 +7528,7 @@ Decl *Sema::ActOnField(Scope *S, Decl *TagD, /// FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, SourceLocation DeclStart, - Declarator &D, Expr *BitWidth, + Declarator &D, Expr *BitWidth, bool HasInit, AccessSpecifier AS) { IdentifierInfo *II = D.getIdentifier(); SourceLocation Loc = DeclStart; @@ -7405,8 +7577,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, = (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable); SourceLocation TSSL = D.getSourceRange().getBegin(); FieldDecl *NewFD - = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, TSSL, - AS, PrevDecl, &D); + = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, HasInit, + TSSL, AS, PrevDecl, &D); if (NewFD->isInvalidDecl()) Record->setInvalidDecl(); @@ -7435,7 +7607,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, TypeSourceInfo *TInfo, RecordDecl *Record, SourceLocation Loc, - bool Mutable, Expr *BitWidth, + bool Mutable, Expr *BitWidth, bool HasInit, SourceLocation TSSL, AccessSpecifier AS, NamedDecl *PrevDecl, Declarator *D) { @@ -7515,7 +7687,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, } FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo, - BitWidth, Mutable); + BitWidth, Mutable, HasInit); if (InvalidDecl) NewFD->setInvalidDecl(); @@ -7535,8 +7707,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, // destructor, or a non-trivial copy assignment operator // cannot be a member of a union, nor can an array of such // objects. - // TODO: C++0x alters this restriction significantly. - if (CheckNontrivialField(NewFD)) + if (!getLangOptions().CPlusPlus0x && CheckNontrivialField(NewFD)) NewFD->setInvalidDecl(); } } @@ -7582,8 +7753,8 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) { CXXSpecialMember member = CXXInvalid; if (!RDecl->hasTrivialCopyConstructor()) member = CXXCopyConstructor; - else if (!RDecl->hasTrivialConstructor()) - member = CXXConstructor; + else if (!RDecl->hasTrivialDefaultConstructor()) + member = CXXDefaultConstructor; else if (!RDecl->hasTrivialCopyAssignment()) member = CXXCopyAssignment; else if (!RDecl->hasTrivialDestructor()) @@ -7612,7 +7783,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { case CXXInvalid: break; - case CXXConstructor: + case CXXDefaultConstructor: if (RD->hasUserDeclaredConstructor()) { typedef CXXRecordDecl::ctor_iterator ctor_iter; for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce;++ci){ @@ -7633,7 +7804,15 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { case CXXCopyConstructor: if (RD->hasUserDeclaredCopyConstructor()) { SourceLocation CtorLoc = - RD->getCopyConstructor(Context, 0)->getLocation(); + RD->getCopyConstructor(0)->getLocation(); + Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member; + return; + } + break; + + case CXXMoveConstructor: + if (RD->hasUserDeclaredMoveConstructor()) { + SourceLocation CtorLoc = RD->getMoveConstructor()->getLocation(); Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member; return; } @@ -7649,6 +7828,14 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { } break; + case CXXMoveAssignment: + if (RD->hasUserDeclaredMoveAssignment()) { + SourceLocation AssignLoc = RD->getMoveAssignmentOperator()->getLocation(); + Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member; + return; + } + break; + case CXXDestructor: if (RD->hasUserDeclaredDestructor()) { SourceLocation DtorLoc = LookupDestructor(RD)->getLocation(); @@ -7686,8 +7873,8 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { bool (CXXRecordDecl::*hasTrivial)() const; switch (member) { - case CXXConstructor: - hasTrivial = &CXXRecordDecl::hasTrivialConstructor; break; + case CXXDefaultConstructor: + hasTrivial = &CXXRecordDecl::hasTrivialDefaultConstructor; break; case CXXCopyConstructor: hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break; case CXXCopyAssignment: @@ -8047,6 +8234,11 @@ void Sema::ActOnFields(Scope* S, Convs->setAccess(I, (*I)->getAccess()); if (!CXXRecord->isDependentType()) { + // Adjust user-defined destructor exception spec. + if (getLangOptions().CPlusPlus0x && + CXXRecord->hasUserDeclaredDestructor()) + AdjustDestructorExceptionSpec(CXXRecord,CXXRecord->getDestructor()); + // Add any implicitly-declared members to this class. AddImplicitlyDeclaredMembersToClass(CXXRecord); @@ -8095,6 +8287,22 @@ void Sema::ActOnFields(Scope* S, if (!Completed) Record->completeDefinition(); + + // Now that the record is complete, do any delayed exception spec checks + // we were missing. + while (!DelayedDestructorExceptionSpecChecks.empty()) { + const CXXDestructorDecl *Dtor = + DelayedDestructorExceptionSpecChecks.back().first; + if (Dtor->getParent() != Record) + break; + + assert(!Dtor->getParent()->isDependentType() && + "Should not ever add destructors of templates into the list."); + CheckOverridingFunctionExceptionSpec(Dtor, + DelayedDestructorExceptionSpecChecks.back().second); + DelayedDestructorExceptionSpecChecks.pop_back(); + } + } else { ObjCIvarDecl **ClsFields = reinterpret_cast<ObjCIvarDecl**>(RecFields.data()); @@ -8149,7 +8357,7 @@ static bool isRepresentableIntegerValue(ASTContext &Context, unsigned BitWidth = Context.getIntWidth(T); if (Value.isUnsigned() || Value.isNonNegative()) { - if (T->isSignedIntegerType()) + if (T->isSignedIntegerOrEnumerationType()) --BitWidth; return Value.getActiveBits() <= BitWidth; } @@ -8172,8 +8380,8 @@ static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) { }; unsigned BitWidth = Context.getTypeSize(T); - QualType *Types = T->isSignedIntegerType()? SignedIntegralTypes - : UnsignedIntegralTypes; + QualType *Types = T->isSignedIntegerOrEnumerationType()? SignedIntegralTypes + : UnsignedIntegralTypes; for (unsigned I = 0; I != NumTypes; ++I) if (Context.getTypeSize(Types[I]) > BitWidth) return Types[I]; @@ -8307,7 +8515,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // type that is supposed to be large enough to represent the incremented // value, then increment. EnumVal = LastEnumConst->getInitVal(); - EnumVal.setIsSigned(EltTy->isSignedIntegerType()); + EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType()); EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); ++EnumVal; @@ -8331,7 +8539,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // Make the enumerator value match the signedness and size of the // enumerator's type. EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); - EnumVal.setIsSigned(EltTy->isSignedIntegerType()); + EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType()); } return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy, @@ -8589,7 +8797,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, } else { NewTy = BestType; NewWidth = BestWidth; - NewSign = BestType->isSignedIntegerType(); + NewSign = BestType->isSignedIntegerOrEnumerationType(); } // Adjust the APSInt value. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 27632a1..ce99efb 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -111,6 +111,102 @@ namespace { } } +void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) { + assert(Context && "ImplicitExceptionSpecification without an ASTContext"); + // 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>(); + + ExceptionSpecificationType EST = Proto->getExceptionSpecType(); + + // If this function can throw any exceptions, make a note of that. + if (EST == EST_Delayed || EST == EST_MSAny || EST == EST_None) { + ClearExceptions(); + ComputedEST = EST; + return; + } + + // FIXME: If the call to this decl is using any of its default arguments, we + // need to search them for potentially-throwing calls. + + // If this function has a basic noexcept, it doesn't affect the outcome. + if (EST == EST_BasicNoexcept) + return; + + // If we have a throw-all spec at this point, ignore the function. + if (ComputedEST == EST_None) + return; + + // If we're still at noexcept(true) and there's a nothrow() callee, + // change to that specification. + if (EST == EST_DynamicNone) { + if (ComputedEST == EST_BasicNoexcept) + ComputedEST = EST_DynamicNone; + return; + } + + // Check out noexcept specs. + if (EST == EST_ComputedNoexcept) { + FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec(*Context); + assert(NR != FunctionProtoType::NR_NoNoexcept && + "Must have noexcept result for EST_ComputedNoexcept."); + assert(NR != FunctionProtoType::NR_Dependent && + "Should not generate implicit declarations for dependent cases, " + "and don't know how to handle them anyway."); + + // noexcept(false) -> no spec on the new function + if (NR == FunctionProtoType::NR_Throw) { + ClearExceptions(); + ComputedEST = EST_None; + } + // noexcept(true) won't change anything either. + return; + } + + assert(EST == EST_Dynamic && "EST case not considered earlier."); + assert(ComputedEST != EST_None && + "Shouldn't collect exceptions when throw-all is guaranteed."); + ComputedEST = EST_Dynamic; + // Record the exceptions in this function's exception specification. + for (FunctionProtoType::exception_iterator E = Proto->exception_begin(), + EEnd = Proto->exception_end(); + E != EEnd; ++E) + if (ExceptionsSeen.insert(Context->getCanonicalType(*E))) + Exceptions.push_back(*E); +} + +void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) { + if (!E || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed) + return; + + // FIXME: + // + // C++0x [except.spec]p14: + // [An] implicit exception-specification specifies the type-id T if and + // only if T is allowed by the exception-specification of a function directly + // invoked by f’s implicit definition; f shall allow all exceptions if any + // function it directly invokes allows all exceptions, and f shall allow no + // exceptions if every function it directly invokes allows no exceptions. + // + // Note in particular that if an implicit exception-specification is generated + // for a function containing a throw-expression, that specification can still + // be noexcept(true). + // + // Note also that 'directly invoked' is not defined in the standard, and there + // is no indication that we should only consider potentially-evaluated calls. + // + // Ultimately we should implement the intent of the standard: the exception + // specification should be the set of exceptions which can be thrown by the + // implicit definition. For now, we assume that any non-nothrow expression can + // throw any exception. + + if (E->CanThrow(*Context)) + ComputedEST = EST_None; +} + bool Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, SourceLocation EqualLoc) { @@ -393,6 +489,15 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { diag::err_param_default_argument_member_template_redecl) << WhichKind << NewParam->getDefaultArgRange(); + } else if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(New)) { + CXXSpecialMember NewSM = getSpecialMember(Ctor), + OldSM = getSpecialMember(cast<CXXConstructorDecl>(Old)); + if (NewSM != OldSM) { + Diag(NewParam->getLocation(),diag::warn_default_arg_makes_ctor_special) + << NewParam->getDefaultArgRange() << NewSM; + Diag(Old->getLocation(), diag::note_previous_declaration_special) + << OldSM; + } } } } @@ -956,14 +1061,15 @@ bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the -/// bitfield width if there is one and 'InitExpr' specifies the initializer if -/// any. +/// bitfield width if there is one, 'InitExpr' specifies the initializer if +/// one has been parsed, and 'HasDeferredInit' is true if an initializer is +/// present but parsing it has been deferred. Decl * Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, ExprTy *BW, const VirtSpecifiers &VS, - ExprTy *InitExpr, bool IsDefinition, - bool Deleted) { + ExprTy *InitExpr, bool HasDeferredInit, + bool IsDefinition) { const DeclSpec &DS = D.getDeclSpec(); DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); @@ -978,6 +1084,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, assert(isa<CXXRecordDecl>(CurContext)); assert(!DS.isFriendSpecified()); + assert(!Init || !HasDeferredInit); bool isFunc = false; if (D.isFunctionDeclarator()) @@ -1028,7 +1135,6 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, if (isInstField) { CXXScopeSpec &SS = D.getCXXScopeSpec(); - if (SS.isSet() && !SS.isInvalid()) { // The user provided a superfluous scope specifier inside a class // definition: @@ -1050,9 +1156,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, // FIXME: Check for template parameters! // FIXME: Check that the name is an identifier! Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth, - AS); + HasDeferredInit, AS); assert(Member && "HandleField never returns null"); } else { + assert(!HasDeferredInit); + Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition); if (!Member) { return 0; @@ -1123,8 +1231,14 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, if (Init) AddInitializerToDecl(Member, Init, false, DS.getTypeSpecType() == DeclSpec::TST_auto); - if (Deleted) // FIXME: Source location is not very good. - SetDeclDeleted(Member, D.getSourceRange().getBegin()); + else if (DS.getTypeSpecType() == DeclSpec::TST_auto && + DS.getStorageClassSpec() == DeclSpec::SCS_static) { + // C++0x [dcl.spec.auto]p4: 'auto' can only be used in the type of a static + // data member if a brace-or-equal-initializer is provided. + Diag(Loc, diag::err_auto_var_requires_init) + << Name << cast<ValueDecl>(Member)->getType(); + Member->setInvalidDecl(); + } FinalizeDeclaration(Member); @@ -1133,6 +1247,47 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, return Member; } +/// ActOnCXXInClassMemberInitializer - This is invoked after parsing an +/// in-class initializer for a non-static C++ class member. Such parsing +/// is deferred until the class is complete. +void +Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc, + Expr *InitExpr) { + FieldDecl *FD = cast<FieldDecl>(D); + + if (!InitExpr) { + FD->setInvalidDecl(); + FD->removeInClassInitializer(); + return; + } + + ExprResult Init = InitExpr; + if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) { + // FIXME: if there is no EqualLoc, this is list-initialization. + Init = PerformCopyInitialization( + InitializedEntity::InitializeMember(FD), EqualLoc, InitExpr); + if (Init.isInvalid()) { + FD->setInvalidDecl(); + return; + } + + CheckImplicitConversions(Init.get(), EqualLoc); + } + + // C++0x [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + Init = MaybeCreateExprWithCleanups(Init); + if (Init.isInvalid()) { + FD->setInvalidDecl(); + return; + } + + InitExpr = Init.release(); + + FD->setInClassInitializer(InitExpr); +} + /// \brief Find the direct and/or virtual base specifiers that /// correspond to the given base type, for use in base initialization /// within a constructor. @@ -1547,7 +1702,8 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, return true; CXXConstructExpr *ConExpr = cast<CXXConstructExpr>(DelegationInit.get()); - CXXConstructorDecl *Constructor = ConExpr->getConstructor(); + CXXConstructorDecl *Constructor + = ConExpr->getConstructor(); assert(Constructor && "Delegating constructor with no target?"); CheckImplicitConversions(DelegationInit.get(), LParenLoc); @@ -1956,24 +2112,26 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, return false; } - if (FieldBaseElementType->isReferenceType()) { - SemaRef.Diag(Constructor->getLocation(), - diag::err_uninitialized_member_in_ctor) - << (int)Constructor->isImplicit() - << SemaRef.Context.getTagDeclType(Constructor->getParent()) - << 0 << Field->getDeclName(); - SemaRef.Diag(Field->getLocation(), diag::note_declared_at); - return true; - } + if (!Field->getParent()->isUnion()) { + if (FieldBaseElementType->isReferenceType()) { + SemaRef.Diag(Constructor->getLocation(), + diag::err_uninitialized_member_in_ctor) + << (int)Constructor->isImplicit() + << SemaRef.Context.getTagDeclType(Constructor->getParent()) + << 0 << Field->getDeclName(); + SemaRef.Diag(Field->getLocation(), diag::note_declared_at); + return true; + } - if (FieldBaseElementType.isConstQualified()) { - SemaRef.Diag(Constructor->getLocation(), - diag::err_uninitialized_member_in_ctor) - << (int)Constructor->isImplicit() - << SemaRef.Context.getTagDeclType(Constructor->getParent()) - << 1 << Field->getDeclName(); - SemaRef.Diag(Field->getLocation(), diag::note_declared_at); - return true; + if (FieldBaseElementType.isConstQualified()) { + SemaRef.Diag(Constructor->getLocation(), + diag::err_uninitialized_member_in_ctor) + << (int)Constructor->isImplicit() + << SemaRef.Context.getTagDeclType(Constructor->getParent()) + << 1 << Field->getDeclName(); + SemaRef.Diag(Field->getLocation(), diag::note_declared_at); + return true; + } } // Nothing to initialize. @@ -2001,7 +2159,7 @@ struct BaseAndFieldInfo { }; } -static bool CollectFieldInitializer(BaseAndFieldInfo &Info, +static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, FieldDecl *Top, FieldDecl *Field) { // Overwhelmingly common case: we have a direct initializer for this field. @@ -2010,6 +2168,18 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, return false; } + // C++0x [class.base.init]p8: if the entity is a non-static data member that + // has a brace-or-equal-initializer, the entity is initialized as specified + // in [dcl.init]. + if (Field->hasInClassInitializer()) { + Info.AllToInit.push_back( + new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, + SourceLocation(), + SourceLocation(), 0, + SourceLocation())); + return false; + } + if (Info.IIK == IIK_Default && Field->isAnonymousStructOrUnion()) { const RecordType *FieldClassType = Field->getType()->getAs<RecordType>(); assert(FieldClassType && "anonymous struct/union without record type"); @@ -2032,7 +2202,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, // field in the class is also initialized, so exit immediately. return false; } else if ((*FA)->isAnonymousStructOrUnion()) { - if (CollectFieldInitializer(Info, Top, *FA)) + if (CollectFieldInitializer(SemaRef, Info, Top, *FA)) return true; } } @@ -2047,7 +2217,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, // necessary. for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(), EA = FieldClassDecl->field_end(); FA != EA; FA++) { - if (CollectFieldInitializer(Info, Top, *FA)) + if (CollectFieldInitializer(SemaRef, Info, Top, *FA)) return true; } } @@ -2056,7 +2226,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, // Don't try to build an implicit initializer if there were semantic // errors in any of the initializers (and therefore we might be // missing some that the user actually wrote). - if (Info.AnyErrorsInInits) + if (Info.AnyErrorsInInits || Field->isInvalidDecl()) return false; CXXCtorInitializer *Init = 0; @@ -2072,26 +2242,22 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, bool Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor, CXXCtorInitializer *Initializer) { + assert(Initializer->isDelegatingInitializer()); Constructor->setNumCtorInitializers(1); CXXCtorInitializer **initializer = new (Context) CXXCtorInitializer*[1]; memcpy(initializer, &Initializer, sizeof (CXXCtorInitializer*)); Constructor->setCtorInitializers(initializer); - // FIXME: This doesn't catch indirect loops yet - CXXConstructorDecl *Target = Initializer->getTargetConstructor(); - while (Target) { - if (Target == Constructor) { - Diag(Initializer->getSourceLocation(), diag::err_delegating_ctor_loop) - << Constructor; - return true; - } - Target = Target->getTargetConstructor(); + if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) { + MarkDeclarationReferenced(Initializer->getSourceLocation(), Dtor); + DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation()); } + DelegatingCtorDecls.push_back(Constructor); + return false; } - bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, @@ -2192,7 +2358,7 @@ Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, "Incomplete array type is not valid"); continue; } - if (CollectFieldInitializer(Info, *Field, *Field)) + if (CollectFieldInitializer(*this, Info, *Field, *Field)) HadError = true; } @@ -2468,7 +2634,7 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl, HadError = true; // We will treat this as being the only initializer. } - SetDelegatingInitializer(Constructor, *MemInits); + SetDelegatingInitializer(Constructor, MemInits[i]); // Return immediately as the initializer is set. return; } @@ -2805,7 +2971,7 @@ static void CheckAbstractClassUsage(AbstractUsageInfo &Info, CXXMethodDecl *MD) { // No need to do the check on definitions, which require that // the return/param types be complete. - if (MD->isThisDeclarationADefinition()) + if (MD->doesThisDeclarationHaveABody()) return; // For safety's sake, just ignore it if we don't have type source @@ -2871,6 +3037,9 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { for (RecordDecl::field_iterator F = Record->field_begin(), FEnd = Record->field_end(); F != FEnd; ++F) { + if (F->hasInClassInitializer()) + continue; + if (F->getType()->isReferenceType() || (F->getType().isConstQualified() && F->getType()->isScalarType())) { if (!Complained) { @@ -2937,6 +3106,953 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { // instantiated (e.g. meta-functions). This doesn't apply to classes that // have inherited constructors. DeclareInheritedConstructors(Record); + + if (!Record->isDependentType()) + CheckExplicitlyDefaultedMethods(Record); +} + +void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) { + for (CXXRecordDecl::method_iterator MI = Record->method_begin(), + ME = Record->method_end(); + MI != ME; ++MI) { + if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted()) { + switch (getSpecialMember(*MI)) { + case CXXDefaultConstructor: + CheckExplicitlyDefaultedDefaultConstructor( + cast<CXXConstructorDecl>(*MI)); + break; + + case CXXDestructor: + CheckExplicitlyDefaultedDestructor(cast<CXXDestructorDecl>(*MI)); + break; + + case CXXCopyConstructor: + CheckExplicitlyDefaultedCopyConstructor(cast<CXXConstructorDecl>(*MI)); + break; + + case CXXCopyAssignment: + CheckExplicitlyDefaultedCopyAssignment(*MI); + break; + + case CXXMoveConstructor: + case CXXMoveAssignment: + Diag(MI->getLocation(), diag::err_defaulted_move_unsupported); + break; + + default: + // FIXME: Do moves once they exist + llvm_unreachable("non-special member explicitly defaulted!"); + } + } + } + +} + +void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) { + assert(CD->isExplicitlyDefaulted() && CD->isDefaultConstructor()); + + // Whether this was the first-declared instance of the constructor. + // This affects whether we implicitly add an exception spec (and, eventually, + // constexpr). It is also ill-formed to explicitly default a constructor such + // that it would be deleted. (C++0x [decl.fct.def.default]) + bool First = CD == CD->getCanonicalDecl(); + + bool HadError = false; + if (CD->getNumParams() != 0) { + Diag(CD->getLocation(), diag::err_defaulted_default_ctor_params) + << CD->getSourceRange(); + HadError = true; + } + + ImplicitExceptionSpecification Spec + = ComputeDefaultedDefaultCtorExceptionSpec(CD->getParent()); + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + if (EPI.ExceptionSpecType == EST_Delayed) { + // Exception specification depends on some deferred part of the class. We'll + // try again when the class's definition has been fully processed. + return; + } + const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(), + *ExceptionType = Context.getFunctionType( + Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); + + if (CtorType->hasExceptionSpec()) { + if (CheckEquivalentExceptionSpec( + PDiag(diag::err_incorrect_defaulted_exception_spec) + << CXXDefaultConstructor, + PDiag(), + ExceptionType, SourceLocation(), + CtorType, CD->getLocation())) { + HadError = true; + } + } else if (First) { + // We set the declaration to have the computed exception spec here. + // We know there are no parameters. + EPI.ExtInfo = CtorType->getExtInfo(); + CD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); + } + + if (HadError) { + CD->setInvalidDecl(); + return; + } + + if (ShouldDeleteDefaultConstructor(CD)) { + if (First) { + CD->setDeletedAsWritten(); + } else { + Diag(CD->getLocation(), diag::err_out_of_line_default_deletes) + << CXXDefaultConstructor; + CD->setInvalidDecl(); + } + } +} + +void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) { + assert(CD->isExplicitlyDefaulted() && CD->isCopyConstructor()); + + // Whether this was the first-declared instance of the constructor. + bool First = CD == CD->getCanonicalDecl(); + + bool HadError = false; + if (CD->getNumParams() != 1) { + Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_params) + << CD->getSourceRange(); + HadError = true; + } + + ImplicitExceptionSpecification Spec(Context); + bool Const; + llvm::tie(Spec, Const) = + ComputeDefaultedCopyCtorExceptionSpecAndConst(CD->getParent()); + + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(), + *ExceptionType = Context.getFunctionType( + Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); + + // Check for parameter type matching. + // This is a copy ctor so we know it's a cv-qualified reference to T. + QualType ArgType = CtorType->getArgType(0); + if (ArgType->getPointeeType().isVolatileQualified()) { + Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_volatile_param); + HadError = true; + } + if (ArgType->getPointeeType().isConstQualified() && !Const) { + Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_const_param); + HadError = true; + } + + if (CtorType->hasExceptionSpec()) { + if (CheckEquivalentExceptionSpec( + PDiag(diag::err_incorrect_defaulted_exception_spec) + << CXXCopyConstructor, + PDiag(), + ExceptionType, SourceLocation(), + CtorType, CD->getLocation())) { + HadError = true; + } + } else if (First) { + // We set the declaration to have the computed exception spec here. + // We duplicate the one parameter type. + EPI.ExtInfo = CtorType->getExtInfo(); + CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); + } + + if (HadError) { + CD->setInvalidDecl(); + return; + } + + if (ShouldDeleteCopyConstructor(CD)) { + if (First) { + CD->setDeletedAsWritten(); + } else { + Diag(CD->getLocation(), diag::err_out_of_line_default_deletes) + << CXXCopyConstructor; + CD->setInvalidDecl(); + } + } +} + +void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) { + assert(MD->isExplicitlyDefaulted()); + + // Whether this was the first-declared instance of the operator + bool First = MD == MD->getCanonicalDecl(); + + bool HadError = false; + if (MD->getNumParams() != 1) { + Diag(MD->getLocation(), diag::err_defaulted_copy_assign_params) + << MD->getSourceRange(); + HadError = true; + } + + QualType ReturnType = + MD->getType()->getAs<FunctionType>()->getResultType(); + if (!ReturnType->isLValueReferenceType() || + !Context.hasSameType( + Context.getCanonicalType(ReturnType->getPointeeType()), + Context.getCanonicalType(Context.getTypeDeclType(MD->getParent())))) { + Diag(MD->getLocation(), diag::err_defaulted_copy_assign_return_type); + HadError = true; + } + + ImplicitExceptionSpecification Spec(Context); + bool Const; + llvm::tie(Spec, Const) = + ComputeDefaultedCopyCtorExceptionSpecAndConst(MD->getParent()); + + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + const FunctionProtoType *OperType = MD->getType()->getAs<FunctionProtoType>(), + *ExceptionType = Context.getFunctionType( + Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); + + QualType ArgType = OperType->getArgType(0); + if (!ArgType->isReferenceType()) { + Diag(MD->getLocation(), diag::err_defaulted_copy_assign_not_ref); + HadError = true; + } else { + if (ArgType->getPointeeType().isVolatileQualified()) { + Diag(MD->getLocation(), diag::err_defaulted_copy_assign_volatile_param); + HadError = true; + } + if (ArgType->getPointeeType().isConstQualified() && !Const) { + Diag(MD->getLocation(), diag::err_defaulted_copy_assign_const_param); + HadError = true; + } + } + + if (OperType->getTypeQuals()) { + Diag(MD->getLocation(), diag::err_defaulted_copy_assign_quals); + HadError = true; + } + + if (OperType->hasExceptionSpec()) { + if (CheckEquivalentExceptionSpec( + PDiag(diag::err_incorrect_defaulted_exception_spec) + << CXXCopyAssignment, + PDiag(), + ExceptionType, SourceLocation(), + OperType, MD->getLocation())) { + HadError = true; + } + } else if (First) { + // We set the declaration to have the computed exception spec here. + // We duplicate the one parameter type. + EPI.RefQualifier = OperType->getRefQualifier(); + EPI.ExtInfo = OperType->getExtInfo(); + MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI)); + } + + if (HadError) { + MD->setInvalidDecl(); + return; + } + + if (ShouldDeleteCopyAssignmentOperator(MD)) { + if (First) { + MD->setDeletedAsWritten(); + } else { + Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) + << CXXCopyAssignment; + MD->setInvalidDecl(); + } + } +} + +void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) { + assert(DD->isExplicitlyDefaulted()); + + // Whether this was the first-declared instance of the destructor. + bool First = DD == DD->getCanonicalDecl(); + + ImplicitExceptionSpecification Spec + = ComputeDefaultedDtorExceptionSpec(DD->getParent()); + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + const FunctionProtoType *DtorType = DD->getType()->getAs<FunctionProtoType>(), + *ExceptionType = Context.getFunctionType( + Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); + + if (DtorType->hasExceptionSpec()) { + if (CheckEquivalentExceptionSpec( + PDiag(diag::err_incorrect_defaulted_exception_spec) + << CXXDestructor, + PDiag(), + ExceptionType, SourceLocation(), + DtorType, DD->getLocation())) { + DD->setInvalidDecl(); + return; + } + } else if (First) { + // We set the declaration to have the computed exception spec here. + // There are no parameters. + EPI.ExtInfo = DtorType->getExtInfo(); + DD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); + } + + if (ShouldDeleteDestructor(DD)) { + if (First) { + DD->setDeletedAsWritten(); + } else { + Diag(DD->getLocation(), diag::err_out_of_line_default_deletes) + << CXXDestructor; + DD->setInvalidDecl(); + } + } +} + +bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { + CXXRecordDecl *RD = CD->getParent(); + assert(!RD->isDependentType() && "do deletion after instantiation"); + if (!LangOpts.CPlusPlus0x) + return false; + + SourceLocation Loc = CD->getLocation(); + + // Do access control from the constructor + ContextRAII CtorContext(*this, CD); + + bool Union = RD->isUnion(); + bool AllConst = true; + + // We do this because we should never actually use an anonymous + // union's constructor. + if (Union && RD->isAnonymousStructOrUnion()) + return false; + + // FIXME: We should put some diagnostic logic right into this function. + + // C++0x [class.ctor]/5 + // A defaulted default constructor for class X is defined as deleted if: + + for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), + BE = RD->bases_end(); + BI != BE; ++BI) { + // We'll handle this one later + if (BI->isVirtual()) + continue; + + CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl(); + assert(BaseDecl && "base isn't a CXXRecordDecl"); + + // -- any [direct base class] has a type with a destructor that is + // deleted or inaccessible from the defaulted default constructor + CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); + if (BaseDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != + AR_accessible) + return true; + + // -- any [direct base class either] has no default constructor or + // overload resolution as applied to [its] default constructor + // results in an ambiguity or in a function that is deleted or + // inaccessible from the defaulted default constructor + CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl); + if (!BaseDefault || BaseDefault->isDeleted()) + return true; + + if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(), + PDiag()) != AR_accessible) + return true; + } + + for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(), + BE = RD->vbases_end(); + BI != BE; ++BI) { + CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl(); + assert(BaseDecl && "base isn't a CXXRecordDecl"); + + // -- any [virtual base class] has a type with a destructor that is + // delete or inaccessible from the defaulted default constructor + CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); + if (BaseDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != + AR_accessible) + return true; + + // -- any [virtual base class either] has no default constructor or + // overload resolution as applied to [its] default constructor + // results in an ambiguity or in a function that is deleted or + // inaccessible from the defaulted default constructor + CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl); + if (!BaseDefault || BaseDefault->isDeleted()) + return true; + + if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(), + PDiag()) != AR_accessible) + return true; + } + + for (CXXRecordDecl::field_iterator FI = RD->field_begin(), + FE = RD->field_end(); + FI != FE; ++FI) { + if (FI->isInvalidDecl()) + continue; + + QualType FieldType = Context.getBaseElementType(FI->getType()); + CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); + + // -- any non-static data member with no brace-or-equal-initializer is of + // reference type + if (FieldType->isReferenceType() && !FI->hasInClassInitializer()) + return true; + + // -- X is a union and all its variant members are of const-qualified type + // (or array thereof) + if (Union && !FieldType.isConstQualified()) + AllConst = false; + + if (FieldRecord) { + // -- X is a union-like class that has a variant member with a non-trivial + // default constructor + if (Union && !FieldRecord->hasTrivialDefaultConstructor()) + return true; + + CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord); + if (FieldDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) != + AR_accessible) + return true; + + // -- any non-variant non-static data member of const-qualified type (or + // array thereof) with no brace-or-equal-initializer does not have a + // user-provided default constructor + if (FieldType.isConstQualified() && + !FI->hasInClassInitializer() && + !FieldRecord->hasUserProvidedDefaultConstructor()) + return true; + + if (!Union && FieldRecord->isUnion() && + FieldRecord->isAnonymousStructOrUnion()) { + // We're okay to reuse AllConst here since we only care about the + // value otherwise if we're in a union. + AllConst = true; + + for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(), + UE = FieldRecord->field_end(); + UI != UE; ++UI) { + QualType UnionFieldType = Context.getBaseElementType(UI->getType()); + CXXRecordDecl *UnionFieldRecord = + UnionFieldType->getAsCXXRecordDecl(); + + if (!UnionFieldType.isConstQualified()) + AllConst = false; + + if (UnionFieldRecord && + !UnionFieldRecord->hasTrivialDefaultConstructor()) + return true; + } + + if (AllConst) + return true; + + // Don't try to initialize the anonymous union + // This is technically non-conformant, but sanity demands it. + continue; + } + + // -- any non-static data member with no brace-or-equal-initializer has + // class type M (or array thereof) and either M has no default + // constructor or overload resolution as applied to M's default + // constructor results in an ambiguity or in a function that is deleted + // or inaccessible from the defaulted default constructor. + if (!FI->hasInClassInitializer()) { + CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord); + if (!FieldDefault || FieldDefault->isDeleted()) + return true; + if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(), + PDiag()) != AR_accessible) + return true; + } + } else if (!Union && FieldType.isConstQualified() && + !FI->hasInClassInitializer()) { + // -- any non-variant non-static data member of const-qualified type (or + // array thereof) with no brace-or-equal-initializer does not have a + // user-provided default constructor + return true; + } + } + + if (Union && AllConst) + return true; + + return false; +} + +bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { + CXXRecordDecl *RD = CD->getParent(); + assert(!RD->isDependentType() && "do deletion after instantiation"); + if (!LangOpts.CPlusPlus0x) + return false; + + SourceLocation Loc = CD->getLocation(); + + // Do access control from the constructor + ContextRAII CtorContext(*this, CD); + + bool Union = RD->isUnion(); + + assert(!CD->getParamDecl(0)->getType()->getPointeeType().isNull() && + "copy assignment arg has no pointee type"); + unsigned ArgQuals = + CD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ? + Qualifiers::Const : 0; + + // We do this because we should never actually use an anonymous + // union's constructor. + if (Union && RD->isAnonymousStructOrUnion()) + return false; + + // FIXME: We should put some diagnostic logic right into this function. + + // C++0x [class.copy]/11 + // A defaulted [copy] constructor for class X is defined as delete if X has: + + for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), + BE = RD->bases_end(); + BI != BE; ++BI) { + // We'll handle this one later + if (BI->isVirtual()) + continue; + + QualType BaseType = BI->getType(); + CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl(); + assert(BaseDecl && "base isn't a CXXRecordDecl"); + + // -- any [direct base class] of a type with a destructor that is deleted or + // inaccessible from the defaulted constructor + CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); + if (BaseDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != + AR_accessible) + return true; + + // -- a [direct base class] B that cannot be [copied] because overload + // resolution, as applied to B's [copy] constructor, results in an + // ambiguity or a function that is deleted or inaccessible from the + // defaulted constructor + CXXConstructorDecl *BaseCtor = LookupCopyConstructor(BaseDecl, ArgQuals); + if (!BaseCtor || BaseCtor->isDeleted()) + return true; + if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) != + AR_accessible) + return true; + } + + for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(), + BE = RD->vbases_end(); + BI != BE; ++BI) { + QualType BaseType = BI->getType(); + CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl(); + assert(BaseDecl && "base isn't a CXXRecordDecl"); + + // -- any [virtual base class] of a type with a destructor that is deleted or + // inaccessible from the defaulted constructor + CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); + if (BaseDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != + AR_accessible) + return true; + + // -- a [virtual base class] B that cannot be [copied] because overload + // resolution, as applied to B's [copy] constructor, results in an + // ambiguity or a function that is deleted or inaccessible from the + // defaulted constructor + CXXConstructorDecl *BaseCtor = LookupCopyConstructor(BaseDecl, ArgQuals); + if (!BaseCtor || BaseCtor->isDeleted()) + return true; + if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) != + AR_accessible) + return true; + } + + for (CXXRecordDecl::field_iterator FI = RD->field_begin(), + FE = RD->field_end(); + FI != FE; ++FI) { + QualType FieldType = Context.getBaseElementType(FI->getType()); + + // -- for a copy constructor, a non-static data member of rvalue reference + // type + if (FieldType->isRValueReferenceType()) + return true; + + CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); + + if (FieldRecord) { + // This is an anonymous union + if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) { + // Anonymous unions inside unions do not variant members create + if (!Union) { + for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(), + UE = FieldRecord->field_end(); + UI != UE; ++UI) { + QualType UnionFieldType = Context.getBaseElementType(UI->getType()); + CXXRecordDecl *UnionFieldRecord = + UnionFieldType->getAsCXXRecordDecl(); + + // -- a variant member with a non-trivial [copy] constructor and X + // is a union-like class + if (UnionFieldRecord && + !UnionFieldRecord->hasTrivialCopyConstructor()) + return true; + } + } + + // Don't try to initalize an anonymous union + continue; + } else { + // -- a variant member with a non-trivial [copy] constructor and X is a + // union-like class + if (Union && !FieldRecord->hasTrivialCopyConstructor()) + return true; + + // -- any [non-static data member] of a type with a destructor that is + // deleted or inaccessible from the defaulted constructor + CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord); + if (FieldDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) != + AR_accessible) + return true; + } + + // -- a [non-static data member of class type (or array thereof)] B that + // cannot be [copied] because overload resolution, as applied to B's + // [copy] constructor, results in an ambiguity or a function that is + // deleted or inaccessible from the defaulted constructor + CXXConstructorDecl *FieldCtor = LookupCopyConstructor(FieldRecord, + ArgQuals); + if (!FieldCtor || FieldCtor->isDeleted()) + return true; + if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(), + PDiag()) != AR_accessible) + return true; + } + } + + return false; +} + +bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { + CXXRecordDecl *RD = MD->getParent(); + assert(!RD->isDependentType() && "do deletion after instantiation"); + if (!LangOpts.CPlusPlus0x) + return false; + + SourceLocation Loc = MD->getLocation(); + + // Do access control from the constructor + ContextRAII MethodContext(*this, MD); + + bool Union = RD->isUnion(); + + bool ConstArg = + MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified(); + + // We do this because we should never actually use an anonymous + // union's constructor. + if (Union && RD->isAnonymousStructOrUnion()) + return false; + + DeclarationName OperatorName = + Context.DeclarationNames.getCXXOperatorName(OO_Equal); + LookupResult R(*this, OperatorName, Loc, LookupOrdinaryName); + R.suppressDiagnostics(); + + // FIXME: We should put some diagnostic logic right into this function. + + // C++0x [class.copy]/11 + // A defaulted [copy] assignment operator for class X is defined as deleted + // if X has: + + for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), + BE = RD->bases_end(); + BI != BE; ++BI) { + // We'll handle this one later + if (BI->isVirtual()) + continue; + + QualType BaseType = BI->getType(); + CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl(); + assert(BaseDecl && "base isn't a CXXRecordDecl"); + + // -- a [direct base class] B that cannot be [copied] because overload + // resolution, as applied to B's [copy] assignment operator, results in + // an ambiguity or a function that is deleted or inaccessible from the + // assignment operator + + LookupQualifiedName(R, BaseDecl, false); + + // Filter out any result that isn't a copy-assignment operator. + LookupResult::Filter F = R.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) + if (Method->isCopyAssignmentOperator()) + continue; + + F.erase(); + } + F.done(); + + // Build a fake argument expression + QualType ArgType = BaseType; + QualType ThisType = BaseType; + if (ConstArg) + ArgType.addConst(); + Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue) + , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue) + }; + + OverloadCandidateSet OCS((Loc)); + OverloadCandidateSet::iterator Best; + + AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS); + + if (OCS.BestViableFunction(*this, Loc, Best, false) != + OR_Success) + return true; + } + + for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(), + BE = RD->vbases_end(); + BI != BE; ++BI) { + QualType BaseType = BI->getType(); + CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl(); + assert(BaseDecl && "base isn't a CXXRecordDecl"); + + // -- a [virtual base class] B that cannot be [copied] because overload + // resolution, as applied to B's [copy] assignment operator, results in + // an ambiguity or a function that is deleted or inaccessible from the + // assignment operator + + LookupQualifiedName(R, BaseDecl, false); + + // Filter out any result that isn't a copy-assignment operator. + LookupResult::Filter F = R.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) + if (Method->isCopyAssignmentOperator()) + continue; + + F.erase(); + } + F.done(); + + // Build a fake argument expression + QualType ArgType = BaseType; + QualType ThisType = BaseType; + if (ConstArg) + ArgType.addConst(); + Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue) + , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue) + }; + + OverloadCandidateSet OCS((Loc)); + OverloadCandidateSet::iterator Best; + + AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS); + + if (OCS.BestViableFunction(*this, Loc, Best, false) != + OR_Success) + return true; + } + + for (CXXRecordDecl::field_iterator FI = RD->field_begin(), + FE = RD->field_end(); + FI != FE; ++FI) { + QualType FieldType = Context.getBaseElementType(FI->getType()); + + // -- a non-static data member of reference type + if (FieldType->isReferenceType()) + return true; + + // -- a non-static data member of const non-class type (or array thereof) + if (FieldType.isConstQualified() && !FieldType->isRecordType()) + return true; + + CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); + + if (FieldRecord) { + // This is an anonymous union + if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) { + // Anonymous unions inside unions do not variant members create + if (!Union) { + for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(), + UE = FieldRecord->field_end(); + UI != UE; ++UI) { + QualType UnionFieldType = Context.getBaseElementType(UI->getType()); + CXXRecordDecl *UnionFieldRecord = + UnionFieldType->getAsCXXRecordDecl(); + + // -- a variant member with a non-trivial [copy] assignment operator + // and X is a union-like class + if (UnionFieldRecord && + !UnionFieldRecord->hasTrivialCopyAssignment()) + return true; + } + } + + // Don't try to initalize an anonymous union + continue; + // -- a variant member with a non-trivial [copy] assignment operator + // and X is a union-like class + } else if (Union && !FieldRecord->hasTrivialCopyAssignment()) { + return true; + } + + LookupQualifiedName(R, FieldRecord, false); + + // Filter out any result that isn't a copy-assignment operator. + LookupResult::Filter F = R.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) + if (Method->isCopyAssignmentOperator()) + continue; + + F.erase(); + } + F.done(); + + // Build a fake argument expression + QualType ArgType = FieldType; + QualType ThisType = FieldType; + if (ConstArg) + ArgType.addConst(); + Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue) + , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue) + }; + + OverloadCandidateSet OCS((Loc)); + OverloadCandidateSet::iterator Best; + + AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS); + + if (OCS.BestViableFunction(*this, Loc, Best, false) != + OR_Success) + return true; + } + } + + return false; +} + +bool Sema::ShouldDeleteDestructor(CXXDestructorDecl *DD) { + CXXRecordDecl *RD = DD->getParent(); + assert(!RD->isDependentType() && "do deletion after instantiation"); + if (!LangOpts.CPlusPlus0x) + return false; + + SourceLocation Loc = DD->getLocation(); + + // Do access control from the destructor + ContextRAII CtorContext(*this, DD); + + bool Union = RD->isUnion(); + + // We do this because we should never actually use an anonymous + // union's destructor. + if (Union && RD->isAnonymousStructOrUnion()) + return false; + + // C++0x [class.dtor]p5 + // A defaulted destructor for a class X is defined as deleted if: + for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), + BE = RD->bases_end(); + BI != BE; ++BI) { + // We'll handle this one later + if (BI->isVirtual()) + continue; + + CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl(); + CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); + assert(BaseDtor && "base has no destructor"); + + // -- any direct or virtual base class has a deleted destructor or + // a destructor that is inaccessible from the defaulted destructor + if (BaseDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != + AR_accessible) + return true; + } + + for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(), + BE = RD->vbases_end(); + BI != BE; ++BI) { + CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl(); + CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); + assert(BaseDtor && "base has no destructor"); + + // -- any direct or virtual base class has a deleted destructor or + // a destructor that is inaccessible from the defaulted destructor + if (BaseDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != + AR_accessible) + return true; + } + + for (CXXRecordDecl::field_iterator FI = RD->field_begin(), + FE = RD->field_end(); + FI != FE; ++FI) { + QualType FieldType = Context.getBaseElementType(FI->getType()); + CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); + if (FieldRecord) { + if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) { + for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(), + UE = FieldRecord->field_end(); + UI != UE; ++UI) { + QualType UnionFieldType = Context.getBaseElementType(FI->getType()); + CXXRecordDecl *UnionFieldRecord = + UnionFieldType->getAsCXXRecordDecl(); + + // -- X is a union-like class that has a variant member with a non- + // trivial destructor. + if (UnionFieldRecord && !UnionFieldRecord->hasTrivialDestructor()) + return true; + } + // Technically we are supposed to do this next check unconditionally. + // But that makes absolutely no sense. + } else { + CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord); + + // -- any of the non-static data members has class type M (or array + // thereof) and M has a deleted destructor or a destructor that is + // inaccessible from the defaulted destructor + if (FieldDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) != + AR_accessible) + return true; + + // -- X is a union-like class that has a variant member with a non- + // trivial destructor. + if (Union && !FieldDtor->isTrivial()) + return true; + } + } + } + + if (DD->isVirtual()) { + FunctionDecl *OperatorDelete = 0; + DeclarationName Name = + Context.DeclarationNames.getCXXOperatorName(OO_Delete); + if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete, + false)) + return true; + } + + + return false; } /// \brief Data used with FindHiddenVirtualMethod @@ -3053,113 +4169,6 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, dyn_cast_or_null<CXXRecordDecl>(TagDecl)); } -namespace { - /// \brief Helper class that collects exception specifications for - /// implicitly-declared special member functions. - class ImplicitExceptionSpecification { - ASTContext &Context; - // We order exception specifications thus: - // noexcept is the most restrictive, but is only used in C++0x. - // throw() comes next. - // Then a throw(collected exceptions) - // Finally no specification. - // throw(...) is used instead if any called function uses it. - ExceptionSpecificationType ComputedEST; - llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen; - llvm::SmallVector<QualType, 4> Exceptions; - - void ClearExceptions() { - ExceptionsSeen.clear(); - Exceptions.clear(); - } - - public: - explicit ImplicitExceptionSpecification(ASTContext &Context) - : Context(Context), ComputedEST(EST_BasicNoexcept) { - if (!Context.getLangOptions().CPlusPlus0x) - ComputedEST = EST_DynamicNone; - } - - /// \brief Get the computed exception specification type. - ExceptionSpecificationType getExceptionSpecType() const { - assert(ComputedEST != EST_ComputedNoexcept && - "noexcept(expr) should not be a possible result"); - return ComputedEST; - } - - /// \brief The number of exceptions in the exception specification. - unsigned size() const { return Exceptions.size(); } - - /// \brief The set of exceptions in the exception specification. - const QualType *data() const { return Exceptions.data(); } - - /// \brief Integrate another called method into the collected data. - void CalledDecl(CXXMethodDecl *Method) { - // If we have an MSAny spec already, don't bother. - if (!Method || ComputedEST == EST_MSAny) - return; - - const FunctionProtoType *Proto - = Method->getType()->getAs<FunctionProtoType>(); - - ExceptionSpecificationType EST = Proto->getExceptionSpecType(); - - // If this function can throw any exceptions, make a note of that. - if (EST == EST_MSAny || EST == EST_None) { - ClearExceptions(); - ComputedEST = EST; - return; - } - - // If this function has a basic noexcept, it doesn't affect the outcome. - if (EST == EST_BasicNoexcept) - return; - - // If we have a throw-all spec at this point, ignore the function. - if (ComputedEST == EST_None) - return; - - // If we're still at noexcept(true) and there's a nothrow() callee, - // change to that specification. - if (EST == EST_DynamicNone) { - if (ComputedEST == EST_BasicNoexcept) - ComputedEST = EST_DynamicNone; - return; - } - - // Check out noexcept specs. - if (EST == EST_ComputedNoexcept) { - FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec(Context); - assert(NR != FunctionProtoType::NR_NoNoexcept && - "Must have noexcept result for EST_ComputedNoexcept."); - assert(NR != FunctionProtoType::NR_Dependent && - "Should not generate implicit declarations for dependent cases, " - "and don't know how to handle them anyway."); - - // noexcept(false) -> no spec on the new function - if (NR == FunctionProtoType::NR_Throw) { - ClearExceptions(); - ComputedEST = EST_None; - } - // noexcept(true) won't change anything either. - return; - } - - assert(EST == EST_Dynamic && "EST case not considered earlier."); - assert(ComputedEST != EST_None && - "Shouldn't collect exceptions when throw-all is guaranteed."); - ComputedEST = EST_Dynamic; - // Record the exceptions in this function's exception specification. - for (FunctionProtoType::exception_iterator E = Proto->exception_begin(), - EEnd = Proto->exception_end(); - E != EEnd; ++E) - if (ExceptionsSeen.insert(Context.getCanonicalType(*E))) - Exceptions.push_back(*E); - } - }; -} - - /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared /// special functions, such as the default constructor, copy /// constructor, or destructor, to the given C++ class (C++ @@ -3467,6 +4476,11 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, if (const TypedefType *TT = DeclaratorType->getAs<TypedefType>()) Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) << DeclaratorType << isa<TypeAliasDecl>(TT->getDecl()); + else if (const TemplateSpecializationType *TST = + DeclaratorType->getAs<TemplateSpecializationType>()) + if (TST->isTypeAlias()) + Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) + << DeclaratorType << 1; // C++ [class.dtor]p2: // A destructor is used to destroy objects of its class type. A @@ -3725,18 +4739,37 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // treated as an original-namespace-name. // // Since namespace names are unique in their scope, and we don't - // look through using directives, just - DeclContext::lookup_result R = CurContext->getRedeclContext()->lookup(II); - NamedDecl *PrevDecl = R.first == R.second? 0 : *R.first; - + // look through using directives, just look for any ordinary names. + + const unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Member | + Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag | + Decl::IDNS_Namespace; + NamedDecl *PrevDecl = 0; + for (DeclContext::lookup_result R + = CurContext->getRedeclContext()->lookup(II); + R.first != R.second; ++R.first) { + if ((*R.first)->getIdentifierNamespace() & IDNS) { + PrevDecl = *R.first; + break; + } + } + if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) { // This is an extended namespace definition. if (Namespc->isInline() != OrigNS->isInline()) { // inline-ness must match - Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch) - << Namespc->isInline(); + if (OrigNS->isInline()) { + // The user probably just forgot the 'inline', so suggest that it + // be added back. + Diag(Namespc->getLocation(), + diag::warn_inline_namespace_reopened_noninline) + << FixItHint::CreateInsertion(NamespaceLoc, "inline "); + } else { + Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch) + << Namespc->isInline(); + } Diag(OrigNS->getLocation(), diag::note_previous_definition); - Namespc->setInvalidDecl(); + // Recover by ignoring the new namespace's inline status. Namespc->setInline(OrigNS->isInline()); } @@ -4408,6 +5441,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, // Otherwise, look up the target name. LookupResult R(*this, NameInfo, LookupOrdinaryName); + R.setUsingDeclaration(true); // Unlike most lookups, we don't always want to hide tag // declarations: tag names are visible through the using declaration @@ -4701,9 +5735,13 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS, + MultiTemplateParamsArg TemplateParamLists, SourceLocation UsingLoc, UnqualifiedId &Name, TypeResult Type) { + // Skip up to the relevant declaration scope. + while (S->getFlags() & Scope::TemplateParamScope) + S = S->getParent(); assert((S->getFlags() & Scope::DeclScope) && "got alias-declaration outside of declaration scope"); @@ -4719,8 +5757,11 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, return 0; if (DiagnoseUnexpandedParameterPack(Name.StartLocation, TInfo, - UPPC_DeclarationType)) + UPPC_DeclarationType)) { Invalid = true; + TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy, + TInfo->getTypeLoc().getBeginLoc()); + } LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); LookupName(Previous, S); @@ -4745,13 +5786,93 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, if (Invalid) NewTD->setInvalidDecl(); + CheckTypedefForVariablyModifiedType(S, NewTD); + Invalid |= NewTD->isInvalidDecl(); + bool Redeclaration = false; - ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration); + + NamedDecl *NewND; + if (TemplateParamLists.size()) { + TypeAliasTemplateDecl *OldDecl = 0; + TemplateParameterList *OldTemplateParams = 0; + + if (TemplateParamLists.size() != 1) { + Diag(UsingLoc, diag::err_alias_template_extra_headers) + << SourceRange(TemplateParamLists.get()[1]->getTemplateLoc(), + TemplateParamLists.get()[TemplateParamLists.size()-1]->getRAngleLoc()); + } + TemplateParameterList *TemplateParams = TemplateParamLists.get()[0]; + + // Only consider previous declarations in the same scope. + FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage*/false, + /*ExplicitInstantiationOrSpecialization*/false); + if (!Previous.empty()) { + Redeclaration = true; + + OldDecl = Previous.getAsSingle<TypeAliasTemplateDecl>(); + if (!OldDecl && !Invalid) { + Diag(UsingLoc, diag::err_redefinition_different_kind) + << Name.Identifier; + + NamedDecl *OldD = Previous.getRepresentativeDecl(); + if (OldD->getLocation().isValid()) + Diag(OldD->getLocation(), diag::note_previous_definition); + + Invalid = true; + } + + if (!Invalid && OldDecl && !OldDecl->isInvalidDecl()) { + if (TemplateParameterListsAreEqual(TemplateParams, + OldDecl->getTemplateParameters(), + /*Complain=*/true, + TPL_TemplateMatch)) + OldTemplateParams = OldDecl->getTemplateParameters(); + else + Invalid = true; + + TypeAliasDecl *OldTD = OldDecl->getTemplatedDecl(); + if (!Invalid && + !Context.hasSameType(OldTD->getUnderlyingType(), + NewTD->getUnderlyingType())) { + // FIXME: The C++0x standard does not clearly say this is ill-formed, + // but we can't reasonably accept it. + Diag(NewTD->getLocation(), diag::err_redefinition_different_typedef) + << 2 << NewTD->getUnderlyingType() << OldTD->getUnderlyingType(); + if (OldTD->getLocation().isValid()) + Diag(OldTD->getLocation(), diag::note_previous_definition); + Invalid = true; + } + } + } + + // Merge any previous default template arguments into our parameters, + // and check the parameter list. + if (CheckTemplateParameterList(TemplateParams, OldTemplateParams, + TPC_TypeAliasTemplate)) + return 0; + + TypeAliasTemplateDecl *NewDecl = + TypeAliasTemplateDecl::Create(Context, CurContext, UsingLoc, + Name.Identifier, TemplateParams, + NewTD); + + NewDecl->setAccess(AS); + + if (Invalid) + NewDecl->setInvalidDecl(); + else if (OldDecl) + NewDecl->setPreviousDeclaration(OldDecl); + + NewND = NewDecl; + } else { + ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration); + NewND = NewTD; + } if (!Redeclaration) - PushOnScopeChains(NewTD, S); + PushOnScopeChains(NewND, S); - return NewTD; + return NewND; } Decl *Sema::ActOnNamespaceAliasDef(Scope *S, @@ -4855,39 +5976,8 @@ namespace { }; } -static CXXConstructorDecl *getDefaultConstructorUnsafe(Sema &Self, - CXXRecordDecl *D) { - ASTContext &Context = Self.Context; - QualType ClassType = Context.getTypeDeclType(D); - DeclarationName ConstructorName - = Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(ClassType.getUnqualifiedType())); - - DeclContext::lookup_const_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName); - Con != ConEnd; ++Con) { - // FIXME: In C++0x, a constructor template can be a default constructor. - if (isa<FunctionTemplateDecl>(*Con)) - continue; - - CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); - if (Constructor->isDefaultConstructor()) - return Constructor; - } - return 0; -} - -CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( - CXXRecordDecl *ClassDecl) { - // C++ [class.ctor]p5: - // A default constructor for a class X is a constructor of class X - // that can be called without an argument. If there is no - // user-declared constructor for class X, a default constructor is - // implicitly declared. An implicitly-declared default constructor - // is an inline public member of its class. - assert(!ClassDecl->hasUserDeclaredConstructor() && - "Should not build implicit default constructor!"); - +Sema::ImplicitExceptionSpecification +Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] @@ -4902,10 +5992,10 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - if (!BaseClassDecl->hasDeclaredDefaultConstructor()) - ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl)); - else if (CXXConstructorDecl *Constructor - = getDefaultConstructorUnsafe(*this, BaseClassDecl)) + CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl); + // 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); } } @@ -4916,10 +6006,10 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( B != BEnd; ++B) { if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - if (!BaseClassDecl->hasDeclaredDefaultConstructor()) - ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl)); - else if (CXXConstructorDecl *Constructor - = getDefaultConstructorUnsafe(*this, BaseClassDecl)) + CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl); + // 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); } } @@ -4928,22 +6018,42 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( for (RecordDecl::field_iterator F = ClassDecl->field_begin(), FEnd = ClassDecl->field_end(); F != FEnd; ++F) { - if (const RecordType *RecordTy + if (F->hasInClassInitializer()) { + if (Expr *E = F->getInClassInitializer()) + ExceptSpec.CalledExpr(E); + else if (!F->isInvalidDecl()) + ExceptSpec.SetDelayed(); + } else if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); - if (!FieldClassDecl->hasDeclaredDefaultConstructor()) - ExceptSpec.CalledDecl( - DeclareImplicitDefaultConstructor(FieldClassDecl)); - else if (CXXConstructorDecl *Constructor - = getDefaultConstructorUnsafe(*this, FieldClassDecl)) + CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); + CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl); + // 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. + // In particular, the problem is that this function never gets called. It + // might just be ill-formed because this function attempts to refer to + // a deleted function here. + if (Constructor) ExceptSpec.CalledDecl(Constructor); } } - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType(); - EPI.NumExceptions = ExceptSpec.size(); - EPI.Exceptions = ExceptSpec.data(); + return ExceptSpec; +} + +CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( + CXXRecordDecl *ClassDecl) { + // C++ [class.ctor]p5: + // A default constructor for a class X is a constructor of class X + // that can be called without an argument. If there is no + // user-declared constructor for class X, a default constructor is + // implicitly declared. An implicitly-declared default constructor + // is an inline public member of its class. + assert(!ClassDecl->hasUserDeclaredConstructor() && + "Should not build implicit default constructor!"); + + ImplicitExceptionSpecification Spec = + ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl); + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); // Create the actual constructor declaration. CanQualType ClassType @@ -4961,8 +6071,9 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( /*isInline=*/true, /*isImplicitlyDeclared=*/true); DefaultCon->setAccess(AS_public); + DefaultCon->setDefaulted(); DefaultCon->setImplicit(); - DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor()); + DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor()); // Note that we have declared this constructor. ++ASTContext::NumImplicitDefaultConstructorsDeclared; @@ -4970,14 +6081,18 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(DefaultCon, S, false); ClassDecl->addDecl(DefaultCon); + + if (ShouldDeleteDefaultConstructor(DefaultCon)) + DefaultCon->setDeletedAsWritten(); return DefaultCon; } void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor) { - assert((Constructor->isImplicit() && Constructor->isDefaultConstructor() && - !Constructor->isUsed(false)) && + assert((Constructor->isDefaulted() && Constructor->isDefaultConstructor() && + !Constructor->doesThisDeclarationHaveABody() && + !Constructor->isDeleted()) && "DefineImplicitDefaultConstructor - call it for implicit default ctor"); CXXRecordDecl *ClassDecl = Constructor->getParent(); @@ -4988,7 +6103,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, if (SetCtorInitializers(Constructor, 0, 0, /*AnyErrors=*/false) || Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXConstructor << Context.getTagDeclType(ClassDecl); + << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl); Constructor->setInvalidDecl(); return; } @@ -5004,6 +6119,59 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, } } +/// Get any existing defaulted default constructor for the given class. Do not +/// implicitly define one if it does not exist. +static CXXConstructorDecl *getDefaultedDefaultConstructorUnsafe(Sema &Self, + CXXRecordDecl *D) { + ASTContext &Context = Self.Context; + QualType ClassType = Context.getTypeDeclType(D); + DeclarationName ConstructorName + = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(ClassType.getUnqualifiedType())); + + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName); + Con != ConEnd; ++Con) { + // A function template cannot be defaulted. + if (isa<FunctionTemplateDecl>(*Con)) + continue; + + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); + if (Constructor->isDefaultConstructor()) + return Constructor->isDefaulted() ? Constructor : 0; + } + return 0; +} + +void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) { + if (!D) return; + AdjustDeclIfTemplate(D); + + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D); + CXXConstructorDecl *CtorDecl + = getDefaultedDefaultConstructorUnsafe(*this, ClassDecl); + + if (!CtorDecl) return; + + // Compute the exception specification for the default constructor. + const FunctionProtoType *CtorTy = + CtorDecl->getType()->castAs<FunctionProtoType>(); + if (CtorTy->getExceptionSpecType() == EST_Delayed) { + ImplicitExceptionSpecification Spec = + ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl); + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + assert(EPI.ExceptionSpecType != EST_Delayed); + + CtorDecl->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); + } + + // If the default constructor is explicitly defaulted, checking the exception + // specification is deferred until now. + if (!CtorDecl->isInvalidDecl() && CtorDecl->isExplicitlyDefaulted() && + !ClassDecl->isDependentType()) + CheckExplicitlyDefaultedDefaultConstructor(CtorDecl); +} + void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { // We start with an initial pass over the base classes to collect those that // inherit constructors from. If there are none, we can forgo all further @@ -5097,7 +6265,9 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { // Build up a function type for this particular constructor. // FIXME: The working paper does not consider that the exception spec // for the inheriting constructor might be larger than that of the - // source. This code doesn't yet, either. + // source. This code doesn't yet, either. When it does, this code will + // need to be delayed until after exception specifications and in-class + // member initializers are attached. const Type *NewCtorType; if (params == maxParams) NewCtorType = BaseCtorType; @@ -5179,12 +6349,8 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { } } -CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { - // C++ [class.dtor]p2: - // If a class has no user-declared destructor, a destructor is - // declared implicitly. An implicitly-declared destructor is an - // inline public member of its class. - +Sema::ImplicitExceptionSpecification +Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) { // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have // an exception-specification. @@ -5199,18 +6365,18 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) ExceptSpec.CalledDecl( - LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl()))); + LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl()))); } - + // Virtual base-class destructors. for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(), BEnd = ClassDecl->vbases_end(); B != BEnd; ++B) { if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) ExceptSpec.CalledDecl( - LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl()))); + LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl()))); } - + // Field destructors. for (RecordDecl::field_iterator F = ClassDecl->field_begin(), FEnd = ClassDecl->field_end(); @@ -5218,14 +6384,23 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs<RecordType>()) ExceptSpec.CalledDecl( - LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl()))); + LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl()))); } + return ExceptSpec; +} + +CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { + // C++ [class.dtor]p2: + // If a class has no user-declared destructor, a destructor is + // declared implicitly. An implicitly-declared destructor is an + // inline public member of its class. + + ImplicitExceptionSpecification Spec = + ComputeDefaultedDtorExceptionSpec(ClassDecl); + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + // Create the actual destructor declaration. - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType(); - EPI.NumExceptions = ExceptSpec.size(); - EPI.Exceptions = ExceptSpec.data(); QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, EPI); CanQualType ClassType @@ -5239,6 +6414,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { /*isInline=*/true, /*isImplicitlyDeclared=*/true); Destructor->setAccess(AS_public); + Destructor->setDefaulted(); Destructor->setImplicit(); Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); @@ -5252,6 +6428,9 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { // This could be uniqued if it ever proves significant. Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty)); + + if (ShouldDeleteDestructor(Destructor)) + Destructor->setDeletedAsWritten(); AddOverriddenMethods(ClassDecl, Destructor); @@ -5260,7 +6439,8 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, CXXDestructorDecl *Destructor) { - assert((Destructor->isImplicit() && !Destructor->isUsed(false)) && + assert((Destructor->isDefaulted() && + !Destructor->doesThisDeclarationHaveABody()) && "DefineImplicitDestructor - call it for implicit default dtor"); CXXRecordDecl *ClassDecl = Destructor->getParent(); assert(ClassDecl && "DefineImplicitDestructor - invalid destructor"); @@ -5293,6 +6473,35 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, } } +void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl, + CXXDestructorDecl *destructor) { + // C++11 [class.dtor]p3: + // A declaration of a destructor that does not have an exception- + // specification is implicitly considered to have the same exception- + // specification as an implicit declaration. + const FunctionProtoType *dtorType = destructor->getType()-> + getAs<FunctionProtoType>(); + if (dtorType->hasExceptionSpec()) + return; + + ImplicitExceptionSpecification exceptSpec = + ComputeDefaultedDtorExceptionSpec(classDecl); + + // Replace the destructor's type. + FunctionProtoType::ExtProtoInfo epi; + epi.ExceptionSpecType = exceptSpec.getExceptionSpecType(); + epi.NumExceptions = exceptSpec.size(); + epi.Exceptions = exceptSpec.data(); + QualType ty = Context.getFunctionType(Context.VoidTy, 0, 0, epi); + + destructor->setType(ty); + + // FIXME: If the destructor has a body that could throw, and the newly created + // spec doesn't allow exceptions, we should emit a warning, because this + // change in behavior can break conforming C++03 programs at runtime. + // However, we don't have a body yet, so it needs to be done somewhere else. +} + /// \brief Builds a statement that copies the given entity from \p From to /// \c To. /// @@ -5530,13 +6739,9 @@ static bool hasConstCopyAssignment(Sema &S, const CXXRecordDecl *CClass) { return false; } -CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { - // Note: The following rules are largely analoguous to the copy - // constructor rules. Note that virtual bases are not taken into account - // for determining the argument type of the operator. Note also that - // operators taking an object instead of a reference are allowed. - - +std::pair<Sema::ImplicitExceptionSpecification, bool> +Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( + CXXRecordDecl *ClassDecl) { // C++ [class.copy]p10: // If the class definition does not explicitly declare a copy // assignment operator, one is declared implicitly. @@ -5581,11 +6786,6 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { // have the form // // X& X::operator=(X&) - QualType ArgType = Context.getTypeDeclType(ClassDecl); - QualType RetType = Context.getLValueReferenceType(ArgType); - if (HasConstCopyAssignment) - ArgType = ArgType.withConst(); - ArgType = Context.getLValueReferenceType(ArgType); // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an @@ -5622,12 +6822,29 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { } } + return std::make_pair(ExceptSpec, HasConstCopyAssignment); +} + +CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { + // Note: The following rules are largely analoguous to the copy + // constructor rules. Note that virtual bases are not taken into account + // for determining the argument type of the operator. Note also that + // operators taking an object instead of a reference are allowed. + + ImplicitExceptionSpecification Spec(Context); + bool Const; + llvm::tie(Spec, Const) = + ComputeDefaultedCopyAssignmentExceptionSpecAndConst(ClassDecl); + + QualType ArgType = Context.getTypeDeclType(ClassDecl); + QualType RetType = Context.getLValueReferenceType(ArgType); + if (Const) + ArgType = ArgType.withConst(); + ArgType = Context.getLValueReferenceType(ArgType); + // An implicitly-declared copy assignment operator is an inline public // member of its class. - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType(); - EPI.NumExceptions = ExceptSpec.size(); - EPI.Exceptions = ExceptSpec.data(); + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationNameInfo NameInfo(Name, ClassLoc); @@ -5639,6 +6856,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { /*isInline=*/true, SourceLocation()); CopyAssignment->setAccess(AS_public); + CopyAssignment->setDefaulted(); CopyAssignment->setImplicit(); CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment()); @@ -5652,21 +6870,24 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { // Note that we have added this copy-assignment operator. ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; - + if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(CopyAssignment, S, false); ClassDecl->addDecl(CopyAssignment); + if (ShouldDeleteCopyAssignmentOperator(CopyAssignment)) + CopyAssignment->setDeletedAsWritten(); + AddOverriddenMethods(ClassDecl, CopyAssignment); return CopyAssignment; } void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CXXMethodDecl *CopyAssignOperator) { - assert((CopyAssignOperator->isImplicit() && + assert((CopyAssignOperator->isDefaulted() && CopyAssignOperator->isOverloadedOperator() && CopyAssignOperator->getOverloadedOperator() == OO_Equal && - !CopyAssignOperator->isUsed(false)) && + !CopyAssignOperator->doesThisDeclarationHaveABody()) && "DefineImplicitCopyAssignment called for wrong function"); CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent(); @@ -5956,12 +7177,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, } } -CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( - CXXRecordDecl *ClassDecl) { - // C++ [class.copy]p4: - // If the class definition does not explicitly declare a copy - // constructor, one is declared implicitly. - +std::pair<Sema::ImplicitExceptionSpecification, bool> +Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { // C++ [class.copy]p5: // The implicitly-declared copy constructor for a class X will // have the form @@ -5969,6 +7186,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // X::X(const X&) // // if + // FIXME: It ought to be possible to store this on the record. bool HasConstCopyConstructor = true; // -- each direct or virtual base class B of X has a copy @@ -5984,11 +7202,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (!BaseClassDecl->hasDeclaredCopyConstructor()) - DeclareImplicitCopyConstructor(BaseClassDecl); - - HasConstCopyConstructor - = BaseClassDecl->hasConstCopyConstructor(Context); + LookupCopyConstructor(BaseClassDecl, Qualifiers::Const, + &HasConstCopyConstructor); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), @@ -5997,11 +7212,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( ++Base) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (!BaseClassDecl->hasDeclaredCopyConstructor()) - DeclareImplicitCopyConstructor(BaseClassDecl); - - HasConstCopyConstructor - = BaseClassDecl->hasConstCopyConstructor(Context); + LookupCopyConstructor(BaseClassDecl, Qualifiers::Const, + &HasConstCopyConstructor); } // -- for all the nonstatic data members of X that are of a @@ -6013,27 +7225,16 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( HasConstCopyConstructor && Field != FieldEnd; ++Field) { QualType FieldType = Context.getBaseElementType((*Field)->getType()); - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - if (!FieldClassDecl->hasDeclaredCopyConstructor()) - DeclareImplicitCopyConstructor(FieldClassDecl); - - HasConstCopyConstructor - = FieldClassDecl->hasConstCopyConstructor(Context); + if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { + LookupCopyConstructor(FieldClassDecl, Qualifiers::Const, + &HasConstCopyConstructor); } } - // Otherwise, the implicitly declared copy constructor will have // the form // // X::X(X&) - QualType ClassType = Context.getTypeDeclType(ClassDecl); - QualType ArgType = ClassType; - if (HasConstCopyConstructor) - ArgType = ArgType.withConst(); - ArgType = Context.getLValueReferenceType(ArgType); - + // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] @@ -6049,11 +7250,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (!BaseClassDecl->hasDeclaredCopyConstructor()) - DeclareImplicitCopyConstructor(BaseClassDecl); - - if (CXXConstructorDecl *CopyConstructor - = BaseClassDecl->getCopyConstructor(Context, Quals)) + if (CXXConstructorDecl *CopyConstructor = + LookupCopyConstructor(BaseClassDecl, Quals)) ExceptSpec.CalledDecl(CopyConstructor); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), @@ -6062,11 +7260,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( ++Base) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (!BaseClassDecl->hasDeclaredCopyConstructor()) - DeclareImplicitCopyConstructor(BaseClassDecl); - - if (CXXConstructorDecl *CopyConstructor - = BaseClassDecl->getCopyConstructor(Context, Quals)) + if (CXXConstructorDecl *CopyConstructor = + LookupCopyConstructor(BaseClassDecl, Quals)) ExceptSpec.CalledDecl(CopyConstructor); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), @@ -6074,29 +7269,43 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( Field != FieldEnd; ++Field) { QualType FieldType = Context.getBaseElementType((*Field)->getType()); - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - if (!FieldClassDecl->hasDeclaredCopyConstructor()) - DeclareImplicitCopyConstructor(FieldClassDecl); - - if (CXXConstructorDecl *CopyConstructor - = FieldClassDecl->getCopyConstructor(Context, Quals)) - ExceptSpec.CalledDecl(CopyConstructor); + if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { + if (CXXConstructorDecl *CopyConstructor = + LookupCopyConstructor(FieldClassDecl, Quals)) + ExceptSpec.CalledDecl(CopyConstructor); } } - // An implicitly-declared copy constructor is an inline public - // member of its class. - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType(); - EPI.NumExceptions = ExceptSpec.size(); - EPI.Exceptions = ExceptSpec.data(); + return std::make_pair(ExceptSpec, HasConstCopyConstructor); +} + +CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( + CXXRecordDecl *ClassDecl) { + // C++ [class.copy]p4: + // If the class definition does not explicitly declare a copy + // constructor, one is declared implicitly. + + ImplicitExceptionSpecification Spec(Context); + bool Const; + llvm::tie(Spec, Const) = + ComputeDefaultedCopyCtorExceptionSpecAndConst(ClassDecl); + + QualType ClassType = Context.getTypeDeclType(ClassDecl); + QualType ArgType = ClassType; + if (Const) + ArgType = ArgType.withConst(); + ArgType = Context.getLValueReferenceType(ArgType); + + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType)); SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationNameInfo NameInfo(Name, ClassLoc); + + // An implicitly-declared copy constructor is an inline public + // member of its class. CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Context.getFunctionType(Context.VoidTy, @@ -6106,6 +7315,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( /*isInline=*/true, /*isImplicitlyDeclared=*/true); CopyConstructor->setAccess(AS_public); + CopyConstructor->setDefaulted(); CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor()); // Note that we have declared this constructor. @@ -6119,19 +7329,22 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( SC_None, SC_None, 0); CopyConstructor->setParams(&FromParam, 1); + if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(CopyConstructor, S, false); ClassDecl->addDecl(CopyConstructor); + + if (ShouldDeleteCopyConstructor(CopyConstructor)) + CopyConstructor->setDeletedAsWritten(); return CopyConstructor; } void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, - CXXConstructorDecl *CopyConstructor, - unsigned TypeQuals) { - assert((CopyConstructor->isImplicit() && - CopyConstructor->isCopyConstructor(TypeQuals) && - !CopyConstructor->isUsed(false)) && + CXXConstructorDecl *CopyConstructor) { + assert((CopyConstructor->isDefaulted() && + CopyConstructor->isCopyConstructor() && + !CopyConstructor->doesThisDeclarationHaveABody()) && "DefineImplicitCopyConstructor - call it for implicit copy ctor"); CXXRecordDecl *ClassDecl = CopyConstructor->getParent(); @@ -7138,7 +8351,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, bool Invalid = false; if (TemplateParameterList *TemplateParams - = MatchTemplateParametersToScopeSpecifier(TagLoc, SS, + = MatchTemplateParametersToScopeSpecifier(TagLoc, NameLoc, SS, TempParamLists.get(), TempParamLists.size(), /*friend*/ true, @@ -7554,7 +8767,83 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { // If the declaration wasn't the first, we delete the function anyway for // recovery. } - Fn->setDeleted(); + Fn->setDeletedAsWritten(); +} + +void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Dcl); + + if (MD) { + if (MD->getParent()->isDependentType()) { + MD->setDefaulted(); + MD->setExplicitlyDefaulted(); + return; + } + + CXXSpecialMember Member = getSpecialMember(MD); + if (Member == CXXInvalid) { + Diag(DefaultLoc, diag::err_default_special_members); + return; + } + + MD->setDefaulted(); + MD->setExplicitlyDefaulted(); + + // If this definition appears within the record, do the checking when + // the record is complete. + const FunctionDecl *Primary = MD; + if (MD->getTemplatedKind() != FunctionDecl::TK_NonTemplate) + // Find the uninstantiated declaration that actually had the '= default' + // on it. + MD->getTemplateInstantiationPattern()->isDefined(Primary); + + if (Primary == Primary->getCanonicalDecl()) + return; + + switch (Member) { + case CXXDefaultConstructor: { + CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD); + CheckExplicitlyDefaultedDefaultConstructor(CD); + if (!CD->isInvalidDecl()) + DefineImplicitDefaultConstructor(DefaultLoc, CD); + break; + } + + case CXXCopyConstructor: { + CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD); + CheckExplicitlyDefaultedCopyConstructor(CD); + if (!CD->isInvalidDecl()) + DefineImplicitCopyConstructor(DefaultLoc, CD); + break; + } + + case CXXCopyAssignment: { + CheckExplicitlyDefaultedCopyAssignment(MD); + if (!MD->isInvalidDecl()) + DefineImplicitCopyAssignment(DefaultLoc, MD); + break; + } + + case CXXDestructor: { + CXXDestructorDecl *DD = cast<CXXDestructorDecl>(MD); + CheckExplicitlyDefaultedDestructor(DD); + if (!DD->isInvalidDecl()) + DefineImplicitDestructor(DefaultLoc, DD); + break; + } + + case CXXMoveConstructor: + case CXXMoveAssignment: + Diag(Dcl->getLocation(), diag::err_defaulted_move_unsupported); + break; + + default: + // FIXME: Do the rest once we have move functions + break; + } + } else { + Diag(DefaultLoc, diag::err_default_special_members); + } } static void SearchForReturnInStmt(Sema &Self, Stmt *S) { @@ -7946,3 +9235,86 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { AllToInit.data(), AllToInit.size()); } } + +static +void DelegatingCycleHelper(CXXConstructorDecl* Ctor, + llvm::SmallSet<CXXConstructorDecl*, 4> &Valid, + llvm::SmallSet<CXXConstructorDecl*, 4> &Invalid, + llvm::SmallSet<CXXConstructorDecl*, 4> &Current, + Sema &S) { + llvm::SmallSet<CXXConstructorDecl*, 4>::iterator CI = Current.begin(), + CE = Current.end(); + if (Ctor->isInvalidDecl()) + return; + + const FunctionDecl *FNTarget = 0; + CXXConstructorDecl *Target; + + // We ignore the result here since if we don't have a body, Target will be + // null below. + (void)Ctor->getTargetConstructor()->hasBody(FNTarget); + Target += const_cast<CXXConstructorDecl*>(cast_or_null<CXXConstructorDecl>(FNTarget)); + + CXXConstructorDecl *Canonical = Ctor->getCanonicalDecl(), + // Avoid dereferencing a null pointer here. + *TCanonical = Target ? Target->getCanonicalDecl() : 0; + + if (!Current.insert(Canonical)) + return; + + // We know that beyond here, we aren't chaining into a cycle. + if (!Target || !Target->isDelegatingConstructor() || + Target->isInvalidDecl() || Valid.count(TCanonical)) { + for (CI = Current.begin(), CE = Current.end(); CI != CE; ++CI) + Valid.insert(*CI); + Current.clear(); + // We've hit a cycle. + } else if (TCanonical == Canonical || Invalid.count(TCanonical) || + Current.count(TCanonical)) { + // If we haven't diagnosed this cycle yet, do so now. + if (!Invalid.count(TCanonical)) { + S.Diag((*Ctor->init_begin())->getSourceLocation(), + diag::warn_delegating_ctor_cycle) + << Ctor; + + // Don't add a note for a function delegating directo to itself. + if (TCanonical != Canonical) + S.Diag(Target->getLocation(), diag::note_it_delegates_to); + + CXXConstructorDecl *C = Target; + while (C->getCanonicalDecl() != Canonical) { + (void)C->getTargetConstructor()->hasBody(FNTarget); + assert(FNTarget && "Ctor cycle through bodiless function"); + + C + = const_cast<CXXConstructorDecl*>(cast<CXXConstructorDecl>(FNTarget)); + S.Diag(C->getLocation(), diag::note_which_delegates_to); + } + } + + for (CI = Current.begin(), CE = Current.end(); CI != CE; ++CI) + Invalid.insert(*CI); + Current.clear(); + } else { + DelegatingCycleHelper(Target, Valid, Invalid, Current, S); + } +} + + +void Sema::CheckDelegatingCtorCycles() { + llvm::SmallSet<CXXConstructorDecl*, 4> Valid, Invalid, Current; + + llvm::SmallSet<CXXConstructorDecl*, 4>::iterator CI = Current.begin(), + CE = Current.end(); + + for (llvm::SmallVector<CXXConstructorDecl*, 4>::iterator + I = DelegatingCtorDecls.begin(), + E = DelegatingCtorDecls.end(); + I != E; ++I) { + DelegatingCycleHelper(*I, Valid, Invalid, Current, *this); + } + + for (CI = Invalid.begin(), CE = Invalid.end(); CI != CE; ++CI) + (*CI)->setInvalidDecl(); +} diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 7b235ba..de9097e 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -24,6 +24,141 @@ using namespace clang; +bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, + const ObjCMethodDecl *Overridden, + bool IsImplementation) { + if (Overridden->hasRelatedResultType() && + !NewMethod->hasRelatedResultType()) { + // This can only happen when the method follows a naming convention that + // implies a related result type, and the original (overridden) method has + // a suitable return type, but the new (overriding) method does not have + // a suitable return type. + QualType ResultType = NewMethod->getResultType(); + SourceRange ResultTypeRange; + if (const TypeSourceInfo *ResultTypeInfo + = NewMethod->getResultTypeSourceInfo()) + ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange(); + + // Figure out which class this method is part of, if any. + ObjCInterfaceDecl *CurrentClass + = dyn_cast<ObjCInterfaceDecl>(NewMethod->getDeclContext()); + if (!CurrentClass) { + DeclContext *DC = NewMethod->getDeclContext(); + if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(DC)) + CurrentClass = Cat->getClassInterface(); + else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(DC)) + CurrentClass = Impl->getClassInterface(); + else if (ObjCCategoryImplDecl *CatImpl + = dyn_cast<ObjCCategoryImplDecl>(DC)) + CurrentClass = CatImpl->getClassInterface(); + } + + if (CurrentClass) { + Diag(NewMethod->getLocation(), + diag::warn_related_result_type_compatibility_class) + << Context.getObjCInterfaceType(CurrentClass) + << ResultType + << ResultTypeRange; + } else { + Diag(NewMethod->getLocation(), + diag::warn_related_result_type_compatibility_protocol) + << ResultType + << ResultTypeRange; + } + + Diag(Overridden->getLocation(), diag::note_related_result_type_overridden) + << Overridden->getMethodFamily(); + } + + return false; +} + + +static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod, + DeclContext *DC, + bool SkipCurrent = true) { + if (!DC) + return false; + + if (!SkipCurrent) { + // Look for this method. If we find it, we're done. + Selector Sel = NewMethod->getSelector(); + bool IsInstance = NewMethod->isInstanceMethod(); + DeclContext::lookup_const_iterator Meth, MethEnd; + for (llvm::tie(Meth, MethEnd) = DC->lookup(Sel); Meth != MethEnd; ++Meth) { + ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); + if (MD && MD->isInstanceMethod() == IsInstance) + return S.CheckObjCMethodOverride(NewMethod, MD, false); + } + } + + if (ObjCInterfaceDecl *Class = llvm::dyn_cast<ObjCInterfaceDecl>(DC)) { + // Look through categories. + for (ObjCCategoryDecl *Category = Class->getCategoryList(); + Category; Category = Category->getNextClassCategory()) { + if (CheckObjCMethodOverrides(S, NewMethod, Category, false)) + return true; + } + + // Look through protocols. + for (ObjCList<ObjCProtocolDecl>::iterator I = Class->protocol_begin(), + IEnd = Class->protocol_end(); + I != IEnd; ++I) + if (CheckObjCMethodOverrides(S, NewMethod, *I, false)) + return true; + + // Look in our superclass. + return CheckObjCMethodOverrides(S, NewMethod, Class->getSuperClass(), + false); + } + + if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) { + // Look through protocols. + for (ObjCList<ObjCProtocolDecl>::iterator I = Category->protocol_begin(), + IEnd = Category->protocol_end(); + I != IEnd; ++I) + if (CheckObjCMethodOverrides(S, NewMethod, *I, false)) + return true; + + return false; + } + + if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) { + // Look through protocols. + for (ObjCList<ObjCProtocolDecl>::iterator I = Protocol->protocol_begin(), + IEnd = Protocol->protocol_end(); + I != IEnd; ++I) + if (CheckObjCMethodOverrides(S, NewMethod, *I, false)) + return true; + + return false; + } + + return false; +} + +bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod, + DeclContext *DC) { + if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(DC)) + return ::CheckObjCMethodOverrides(*this, NewMethod, Class); + + if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) + return ::CheckObjCMethodOverrides(*this, NewMethod, Category); + + if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) + return ::CheckObjCMethodOverrides(*this, NewMethod, Protocol); + + if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(DC)) + return ::CheckObjCMethodOverrides(*this, NewMethod, + Impl->getClassInterface()); + + if (ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(DC)) + return ::CheckObjCMethodOverrides(*this, NewMethod, + CatImpl->getClassInterface()); + + return ::CheckObjCMethodOverrides(*this, NewMethod, CurContext); +} + static void DiagnoseObjCImplementedDeprecations(Sema &S, NamedDecl *ND, SourceLocation ImplLoc, @@ -272,23 +407,27 @@ Decl *Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, return AliasDecl; } -void Sema::CheckForwardProtocolDeclarationForCircularDependency( +bool Sema::CheckForwardProtocolDeclarationForCircularDependency( IdentifierInfo *PName, SourceLocation &Ploc, SourceLocation PrevLoc, const ObjCList<ObjCProtocolDecl> &PList) { + + bool res = false; for (ObjCList<ObjCProtocolDecl>::iterator I = PList.begin(), E = PList.end(); I != E; ++I) { - if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier(), Ploc)) { if (PDecl->getIdentifier() == PName) { Diag(Ploc, diag::err_protocol_has_circular_dependency); Diag(PrevLoc, diag::note_previous_definition); + res = true; } - CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc, - PDecl->getLocation(), PDecl->getReferencedProtocols()); + if (CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc, + PDecl->getLocation(), PDecl->getReferencedProtocols())) + res = true; } } + return res; } Decl * @@ -300,6 +439,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { + bool err = false; // FIXME: Deal with AttrList. assert(ProtocolName && "Missing protocol identifier"); ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName, ProtocolLoc); @@ -314,8 +454,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, } ObjCList<ObjCProtocolDecl> PList; PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context); - CheckForwardProtocolDeclarationForCircularDependency( - ProtocolName, ProtocolLoc, PDecl->getLocation(), PList); + err = CheckForwardProtocolDeclarationForCircularDependency( + ProtocolName, ProtocolLoc, PDecl->getLocation(), PList); // Make sure the cached decl gets a valid start location. PDecl->setLocation(AtProtoInterfaceLoc); @@ -331,7 +471,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, } if (AttrList) ProcessDeclAttributeList(TUScope, PDecl, AttrList); - if (NumProtoRefs) { + if (!err && NumProtoRefs ) { /// Check then save referenced protocols. PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, ProtoLocs, Context); @@ -1712,11 +1852,71 @@ bool containsInvalidMethodImplAttribute(const AttrVec &A) { return false; } +/// \brief Check whether the declared result type of the given Objective-C +/// method declaration is compatible with the method's class. +/// +static bool +CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method, + ObjCInterfaceDecl *CurrentClass) { + QualType ResultType = Method->getResultType(); + SourceRange ResultTypeRange; + if (const TypeSourceInfo *ResultTypeInfo = Method->getResultTypeSourceInfo()) + ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange(); + + // If an Objective-C method inherits its related result type, then its + // declared result type must be compatible with its own class type. The + // declared result type is compatible if: + if (const ObjCObjectPointerType *ResultObjectType + = ResultType->getAs<ObjCObjectPointerType>()) { + // - it is id or qualified id, or + if (ResultObjectType->isObjCIdType() || + ResultObjectType->isObjCQualifiedIdType()) + return false; + + if (CurrentClass) { + if (ObjCInterfaceDecl *ResultClass + = ResultObjectType->getInterfaceDecl()) { + // - it is the same as the method's class type, or + if (CurrentClass == ResultClass) + return false; + + // - it is a superclass of the method's class type + if (ResultClass->isSuperClassOf(CurrentClass)) + return false; + } + } + } + + return true; +} + +/// \brief Determine if any method in the global method pool has an inferred +/// result type. +static bool +anyMethodInfersRelatedResultType(Sema &S, Selector Sel, bool IsInstance) { + Sema::GlobalMethodPool::iterator Pos = S.MethodPool.find(Sel); + if (Pos == S.MethodPool.end()) { + if (S.ExternalSource) + Pos = S.ReadMethodPool(Sel); + else + return 0; + } + + ObjCMethodList &List = IsInstance ? Pos->second.first : Pos->second.second; + for (ObjCMethodList *M = &List; M; M = M->Next) { + if (M->Method && M->Method->hasRelatedResultType()) + return true; + } + + return false; +} + Decl *Sema::ActOnMethodDeclaration( Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc, tok::TokenKind MethodType, Decl *ClassDecl, ObjCDeclSpec &ReturnQT, ParsedType ReturnType, + SourceLocation SelectorStartLoc, Selector Sel, // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). @@ -1741,7 +1941,7 @@ Decl *Sema::ActOnMethodDeclaration( Diag(MethodLoc, diag::err_object_cannot_be_passed_returned_by_value) << 0 << resultDeclType; return 0; - } + } } else // get the type for "id". resultDeclType = Context.getObjCIdType(); @@ -1751,9 +1951,10 @@ Decl *Sema::ActOnMethodDeclaration( cast<DeclContext>(ClassDecl), MethodType == tok::minus, isVariadic, false, false, - MethodDeclKind == tok::objc_optional ? - ObjCMethodDecl::Optional : - ObjCMethodDecl::Required); + MethodDeclKind == tok::objc_optional + ? ObjCMethodDecl::Optional + : ObjCMethodDecl::Required, + false); llvm::SmallVector<ParmVarDecl*, 16> Params; @@ -1849,6 +2050,7 @@ Decl *Sema::ActOnMethodDeclaration( } InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel, MethodType == tok::minus); + if (ObjCMethod->hasAttrs() && containsInvalidMethodImplAttribute(ObjCMethod->getAttrs())) Diag(EndLoc, diag::warn_attribute_method_def); @@ -1861,6 +2063,10 @@ Decl *Sema::ActOnMethodDeclaration( PrevMethod = CatImpDecl->getClassMethod(Sel); CatImpDecl->addClassMethod(ObjCMethod); } + + if (ObjCCategoryDecl *Cat = CatImpDecl->getCategoryDecl()) + InterfaceMD = Cat->getMethod(Sel, MethodType == tok::minus); + if (ObjCMethod->hasAttrs() && containsInvalidMethodImplAttribute(ObjCMethod->getAttrs())) Diag(EndLoc, diag::warn_attribute_method_def); @@ -1874,10 +2080,65 @@ Decl *Sema::ActOnMethodDeclaration( Diag(PrevMethod->getLocation(), diag::note_previous_declaration); } + // If this Objective-C method does not have a related result type, but we + // are allowed to infer related result types, try to do so based on the + // method family. + ObjCInterfaceDecl *CurrentClass = dyn_cast<ObjCInterfaceDecl>(ClassDecl); + if (!CurrentClass) { + if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(ClassDecl)) + CurrentClass = Cat->getClassInterface(); + else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(ClassDecl)) + CurrentClass = Impl->getClassInterface(); + else if (ObjCCategoryImplDecl *CatImpl + = dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) + CurrentClass = CatImpl->getClassInterface(); + } + // Merge information down from the interface declaration if we have one. - if (InterfaceMD) + if (InterfaceMD) { + // Inherit the related result type, if we can. + if (InterfaceMD->hasRelatedResultType() && + !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass)) + ObjCMethod->SetRelatedResultType(); + mergeObjCMethodDecls(ObjCMethod, InterfaceMD); - + } + + if (!ObjCMethod->hasRelatedResultType() && + getLangOptions().ObjCInferRelatedResultType) { + bool InferRelatedResultType = false; + switch (ObjCMethod->getMethodFamily()) { + case OMF_None: + case OMF_copy: + case OMF_dealloc: + case OMF_mutableCopy: + case OMF_release: + case OMF_retainCount: + break; + + case OMF_alloc: + case OMF_new: + InferRelatedResultType = ObjCMethod->isClassMethod(); + break; + + case OMF_init: + case OMF_autorelease: + case OMF_retain: + case OMF_self: + InferRelatedResultType = ObjCMethod->isInstanceMethod(); + break; + } + + if (InferRelatedResultType && + !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass)) + ObjCMethod->SetRelatedResultType(); + + if (!InterfaceMD && + anyMethodInfersRelatedResultType(*this, ObjCMethod->getSelector(), + ObjCMethod->isInstanceMethod())) + CheckObjCMethodOverrides(ObjCMethod, cast<DeclContext>(ClassDecl)); + } + return ObjCMethod; } diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index f1033dc..7bcec31 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -298,8 +298,6 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, // - both are non-throwing, regardless of their form, // - both have the form noexcept(constant-expression) and the constant- // expressions are equivalent, - // - one exception-specification is a noexcept-specification allowing all - // exceptions and the other is of the form throw(type-id-list), or // - both are dynamic-exception-specifications that have the same set of // adjusted types. // @@ -307,8 +305,6 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, // of the form throw(), noexcept, or noexcept(constant-expression) where the // constant-expression yields true. // - // CWG 1073 Proposed resolution: Strike the third bullet above. - // // C++0x [except.spec]p4: If any declaration of a function has an exception- // specifier that is not a noexcept-specification allowing all exceptions, // all declarations [...] of that function shall have a compatible @@ -320,6 +316,9 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, ExceptionSpecificationType OldEST = Old->getExceptionSpecType(); ExceptionSpecificationType NewEST = New->getExceptionSpecType(); + assert(OldEST != EST_Delayed && NewEST != EST_Delayed && + "Shouldn't see unknown exception specifications here"); + // Shortcut the case where both have no spec. if (OldEST == EST_None && NewEST == EST_None) return false; @@ -506,6 +505,9 @@ bool Sema::CheckExceptionSpecSubset( ExceptionSpecificationType SubEST = Subset->getExceptionSpecType(); + assert(SuperEST != EST_Delayed && SubEST != EST_Delayed && + "Shouldn't see unknown exception specifications here"); + // It does not. If the subset contains everything, we've failed. if (SubEST == EST_None || SubEST == EST_MSAny) { Diag(SubLoc, DiagID); @@ -701,7 +703,23 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, const CXXMethodDecl *Old) { - return CheckExceptionSpecSubset(PDiag(diag::err_override_exception_spec), + if (getLangOptions().CPlusPlus0x && isa<CXXDestructorDecl>(New)) { + // Don't check uninstantiated template destructors at all. We can only + // synthesize correct specs after the template is instantiated. + if (New->getParent()->isDependentType()) + return false; + if (New->getParent()->isBeingDefined()) { + // The destructor might be updated once the definition is finished. So + // remember it and check later. + DelayedDestructorExceptionSpecChecks.push_back(std::make_pair( + cast<CXXDestructorDecl>(New), cast<CXXDestructorDecl>(Old))); + return false; + } + } + unsigned DiagID = diag::err_override_exception_spec; + if (getLangOptions().Microsoft) + DiagID = diag::warn_override_exception_spec; + return CheckExceptionSpecSubset(PDiag(DiagID), PDiag(diag::note_overridden_virtual_function), Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 20b92b8..0549e94 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -449,18 +449,58 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, if (FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_va_start) return Owned(E); + // Don't allow one to pass an Objective-C interface to a vararg. if (E->getType()->isObjCObjectType() && - DiagRuntimeBehavior(E->getLocStart(), 0, - PDiag(diag::err_cannot_pass_objc_interface_to_vararg) - << E->getType() << CT)) + DiagRuntimeBehavior(E->getLocStart(), 0, + PDiag(diag::err_cannot_pass_objc_interface_to_vararg) + << E->getType() << CT)) return ExprError(); - - if (!E->getType()->isPODType() && - DiagRuntimeBehavior(E->getLocStart(), 0, + + if (!E->getType()->isPODType()) { + // C++0x [expr.call]p7: + // Passing a potentially-evaluated argument of class type (Clause 9) + // having a non-trivial copy constructor, a non-trivial move constructor, + // or a non-trivial destructor, with no corresponding parameter, + // is conditionally-supported with implementation-defined semantics. + bool TrivialEnough = false; + if (getLangOptions().CPlusPlus0x && !E->getType()->isDependentType()) { + if (CXXRecordDecl *Record = E->getType()->getAsCXXRecordDecl()) { + if (Record->hasTrivialCopyConstructor() && + Record->hasTrivialMoveConstructor() && + Record->hasTrivialDestructor()) + TrivialEnough = true; + } + } + + if (TrivialEnough) { + // Nothing to diagnose. This is okay. + } else if (DiagRuntimeBehavior(E->getLocStart(), 0, PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) - << E->getType() << CT)) - return ExprError(); + << getLangOptions().CPlusPlus0x << E->getType() + << CT)) { + // Turn this into a trap. + CXXScopeSpec SS; + UnqualifiedId Name; + Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"), + E->getLocStart()); + ExprResult TrapFn = ActOnIdExpression(TUScope, SS, Name, true, false); + if (TrapFn.isInvalid()) + return ExprError(); + ExprResult Call = ActOnCallExpr(TUScope, TrapFn.get(), E->getLocStart(), + MultiExprArg(), E->getLocEnd()); + if (Call.isInvalid()) + return ExprError(); + + ExprResult Comma = ActOnBinOp(TUScope, E->getLocStart(), tok::comma, + Call.get(), E); + if (Comma.isInvalid()) + return ExprError(); + + E = Comma.get(); + } + } + return Owned(E); } @@ -1293,8 +1333,8 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, // We've found a member of an anonymous struct/union that is // inside a non-anonymous struct/union, so in a well-formed // program our base object expression is "this". - CXXMethodDecl *method = tryCaptureCXXThis(); - if (!method) { + QualType ThisTy = getAndCaptureCurrentThisType(); + if (ThisTy.isNull()) { Diag(loc, diag::err_invalid_member_use_in_static_method) << indirectField->getDeclName(); return ExprError(); @@ -1302,10 +1342,9 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, // Our base object expression is "this". baseObjectExpr = - new (Context) CXXThisExpr(loc, method->getThisType(Context), - /*isImplicit=*/ true); + new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true); baseObjectIsPointer = true; - baseQuals = Qualifiers::fromCVRMask(method->getTypeQualifiers()); + baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers(); } // Build the implicit member references to the field of the @@ -1452,14 +1491,23 @@ enum IMAKind { /// conservatively answer "yes", in which case some errors will simply /// not be caught until template-instantiation. static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, + Scope *CurScope, const LookupResult &R) { assert(!R.empty() && (*R.begin())->isCXXClassMember()); 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; + if (R.isUnresolvableResult()) return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved; @@ -1507,8 +1555,11 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, return IMA_Error_StaticContext; } - CXXRecordDecl * - contextClass = cast<CXXMethodDecl>(DC)->getParent()->getCanonicalDecl(); + CXXRecordDecl *contextClass; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) + contextClass = MD->getParent()->getCanonicalDecl(); + else + contextClass = cast<CXXRecordDecl>(DC); // [class.mfct.non-static]p3: // ...is used in the body of a non-static member function of class X, @@ -1986,7 +2037,7 @@ ExprResult Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { - switch (ClassifyImplicitMemberAccess(*this, R)) { + switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) { case IMA_Instance: return BuildImplicitMemberExpr(SS, R, TemplateArgs, true); @@ -2429,19 +2480,18 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, // If this is known to be an instance access, go ahead and build an // implicit 'this' expression now. // 'this' expression now. - CXXMethodDecl *method = tryCaptureCXXThis(); - assert(method && "didn't correctly pre-flight capture of 'this'"); + QualType ThisTy = getAndCaptureCurrentThisType(); + assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'"); - QualType thisType = method->getThisType(Context); Expr *baseExpr = 0; // null signifies implicit access if (IsKnownInstance) { SourceLocation Loc = R.getNameLoc(); if (SS.getRange().isValid()) Loc = SS.getRange().getBegin(); - baseExpr = new (Context) CXXThisExpr(loc, thisType, /*isImplicit=*/true); + baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true); } - return BuildMemberReferenceExpr(baseExpr, thisType, + return BuildMemberReferenceExpr(baseExpr, ThisTy, /*OpLoc*/ SourceLocation(), /*IsArrow*/ true, SS, @@ -3014,8 +3064,120 @@ ExprResult Sema::ActOnParenExpr(SourceLocation L, return Owned(new (Context) ParenExpr(L, R, E)); } +static bool CheckVecStepTraitOperandType(Sema &S, QualType T, + SourceLocation Loc, + SourceRange ArgRange) { + // [OpenCL 1.1 6.11.12] "The vec_step built-in function takes a built-in + // scalar or vector data type argument..." + // Every built-in scalar type (OpenCL 1.1 6.1.1) is either an arithmetic + // type (C99 6.2.5p18) or void. + if (!(T->isArithmeticType() || T->isVoidType() || T->isVectorType())) { + S.Diag(Loc, diag::err_vecstep_non_scalar_vector_type) + << T << ArgRange; + return true; + } + + assert((T->isVoidType() || !T->isIncompleteType()) && + "Scalar types should always be complete"); + return false; +} + +static bool CheckExtensionTraitOperandType(Sema &S, QualType T, + SourceLocation Loc, + SourceRange ArgRange, + UnaryExprOrTypeTrait TraitKind) { + // C99 6.5.3.4p1: + if (T->isFunctionType()) { + // alignof(function) is allowed as an extension. + if (TraitKind == UETT_SizeOf) + S.Diag(Loc, diag::ext_sizeof_function_type) << ArgRange; + return false; + } + + // Allow sizeof(void)/alignof(void) as an extension. + if (T->isVoidType()) { + S.Diag(Loc, diag::ext_sizeof_void_type) << TraitKind << ArgRange; + return false; + } + + return true; +} + +static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T, + SourceLocation Loc, + SourceRange ArgRange, + UnaryExprOrTypeTrait TraitKind) { + // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode. + if (S.LangOpts.ObjCNonFragileABI && T->isObjCObjectType()) { + S.Diag(Loc, diag::err_sizeof_nonfragile_interface) + << T << (TraitKind == UETT_SizeOf) + << ArgRange; + return true; + } + + return false; +} + +/// \brief Check the constrains on expression operands to unary type expression +/// and type traits. +/// +/// Completes any types necessary and validates the constraints on the operand +/// expression. The logic mostly mirrors the type-based overload, but may modify +/// the expression as it completes the type for that expression through template +/// instantiation, etc. +bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op, + UnaryExprOrTypeTrait ExprKind) { + QualType ExprTy = Op->getType(); + + // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, + // the result is the size of the referenced type." + // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the + // result shall be the alignment of the referenced type." + if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>()) + ExprTy = Ref->getPointeeType(); + + if (ExprKind == UETT_VecStep) + return CheckVecStepTraitOperandType(*this, ExprTy, Op->getExprLoc(), + Op->getSourceRange()); + + // Whitelist some types as extensions + if (!CheckExtensionTraitOperandType(*this, ExprTy, Op->getExprLoc(), + Op->getSourceRange(), ExprKind)) + return false; + + if (RequireCompleteExprType(Op, + PDiag(diag::err_sizeof_alignof_incomplete_type) + << ExprKind << Op->getSourceRange(), + std::make_pair(SourceLocation(), PDiag(0)))) + return true; + + // Completeing the expression's type may have changed it. + ExprTy = Op->getType(); + if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>()) + ExprTy = Ref->getPointeeType(); + + if (CheckObjCTraitOperandConstraints(*this, ExprTy, Op->getExprLoc(), + Op->getSourceRange(), ExprKind)) + return true; + + return false; +} + +/// \brief Check the constraints on operands to unary expression and type +/// traits. +/// +/// This will complete any types necessary, and validate the various constraints +/// on those operands. +/// /// The UsualUnaryConversions() function is *not* called by this routine. -/// See C99 6.3.2.1p[2-4] for more details. +/// C99 6.3.2.1p[2-4] all state: +/// Except when it is the operand of the sizeof operator ... +/// +/// C++ [expr.sizeof]p4 +/// The lvalue-to-rvalue, array-to-pointer, and function-to-pointer +/// standard conversions are not applied to the operand of sizeof. +/// +/// This policy is followed for all of the unary trait expressions. bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType exprType, SourceLocation OpLoc, SourceRange ExprRange, @@ -3030,55 +3192,27 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType exprType, if (const ReferenceType *Ref = exprType->getAs<ReferenceType>()) exprType = Ref->getPointeeType(); - // [OpenCL 1.1 6.11.12] "The vec_step built-in function takes a built-in - // scalar or vector data type argument..." - // Every built-in scalar type (OpenCL 1.1 6.1.1) is either an arithmetic - // type (C99 6.2.5p18) or void. - if (ExprKind == UETT_VecStep) { - if (!(exprType->isArithmeticType() || exprType->isVoidType() || - exprType->isVectorType())) { - Diag(OpLoc, diag::err_vecstep_non_scalar_vector_type) - << exprType << ExprRange; - return true; - } - } + if (ExprKind == UETT_VecStep) + return CheckVecStepTraitOperandType(*this, exprType, OpLoc, ExprRange); - // C99 6.5.3.4p1: - if (exprType->isFunctionType()) { - // alignof(function) is allowed as an extension. - if (ExprKind == UETT_SizeOf) - Diag(OpLoc, diag::ext_sizeof_function_type) - << ExprRange; + // Whitelist some types as extensions + if (!CheckExtensionTraitOperandType(*this, exprType, OpLoc, ExprRange, + ExprKind)) return false; - } - - // Allow sizeof(void)/alignof(void) as an extension. vec_step(void) is not - // an extension, as void is a built-in scalar type (OpenCL 1.1 6.1.1). - if (exprType->isVoidType()) { - if (ExprKind != UETT_VecStep) - Diag(OpLoc, diag::ext_sizeof_void_type) - << ExprKind << ExprRange; - return false; - } if (RequireCompleteType(OpLoc, exprType, PDiag(diag::err_sizeof_alignof_incomplete_type) << ExprKind << ExprRange)) return true; - // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode. - if (LangOpts.ObjCNonFragileABI && exprType->isObjCObjectType()) { - Diag(OpLoc, diag::err_sizeof_nonfragile_interface) - << exprType << (ExprKind == UETT_SizeOf) - << ExprRange; + if (CheckObjCTraitOperandConstraints(*this, exprType, OpLoc, ExprRange, + ExprKind)) return true; - } return false; } -static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc, - SourceRange ExprRange) { +static bool CheckAlignOfExpr(Sema &S, Expr *E) { E = E->IgnoreParens(); // alignof decl is always ok. @@ -3090,7 +3224,8 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc, return false; if (E->getBitField()) { - S. Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 1 << ExprRange; + S.Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) + << 1 << E->getSourceRange(); return true; } @@ -3100,20 +3235,17 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc, if (isa<FieldDecl>(ME->getMemberDecl())) return false; - return S.CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange, - UETT_AlignOf); + return S.CheckUnaryExprOrTypeTraitOperand(E, UETT_AlignOf); } -bool Sema::CheckVecStepExpr(Expr *E, SourceLocation OpLoc, - SourceRange ExprRange) { +bool Sema::CheckVecStepExpr(Expr *E) { E = E->IgnoreParens(); // Cannot know anything else if the expression is dependent. if (E->isTypeDependent()) return false; - return CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange, - UETT_VecStep); + return CheckUnaryExprOrTypeTraitOperand(E, UETT_VecStep); } /// \brief Build a sizeof or alignof expression given a type operand. @@ -3141,35 +3273,33 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, /// operand. ExprResult Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, - UnaryExprOrTypeTrait ExprKind, - SourceRange R) { + UnaryExprOrTypeTrait ExprKind) { // Verify that the operand is valid. bool isInvalid = false; if (E->isTypeDependent()) { // Delay type-checking for type-dependent expressions. } else if (ExprKind == UETT_AlignOf) { - isInvalid = CheckAlignOfExpr(*this, E, OpLoc, R); + isInvalid = CheckAlignOfExpr(*this, E); } else if (ExprKind == UETT_VecStep) { - isInvalid = CheckVecStepExpr(E, OpLoc, R); + isInvalid = CheckVecStepExpr(E); } else if (E->getBitField()) { // C99 6.5.3.4p1. - Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0; + Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 0; isInvalid = true; } else if (E->getType()->isPlaceholderType()) { ExprResult PE = CheckPlaceholderExpr(E); if (PE.isInvalid()) return ExprError(); - return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind, R); + return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind); } else { - isInvalid = CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, R, - UETT_SizeOf); + isInvalid = CheckUnaryExprOrTypeTraitOperand(E, UETT_SizeOf); } if (isInvalid) return ExprError(); // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. - return Owned(new (Context) UnaryExprOrTypeTraitExpr(ExprKind, E, - Context.getSizeType(), - OpLoc, R.getEnd())); + return Owned(new (Context) UnaryExprOrTypeTraitExpr( + ExprKind, E, Context.getSizeType(), OpLoc, + E->getSourceRange().getEnd())); } /// ActOnUnaryExprOrTypeTraitExpr - Handle @c sizeof(type) and @c sizeof @c @@ -3189,10 +3319,7 @@ Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, } Expr *ArgEx = (Expr *)TyOrEx; - ExprResult Result - = CreateUnaryExprOrTypeTraitExpr(ArgEx, OpLoc, ExprKind, - ArgEx->getSourceRange()); - + ExprResult Result = CreateUnaryExprOrTypeTraitExpr(ArgEx, OpLoc, ExprKind); return move(Result); } @@ -4211,7 +4338,11 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); - return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + QualType T = PD->getType(); + if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + T = getMessageSendResultType(BaseType, Getter, false, false); + + return Owned(new (Context) ObjCPropertyRefExpr(PD, T, VK_LValue, OK_ObjCProperty, MemberLoc, @@ -4229,7 +4360,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0, SetterSel, Context)) SMD = dyn_cast<ObjCMethodDecl>(SDecl); - QualType PType = OMD->getSendResultType(); + QualType PType = getMessageSendResultType(BaseType, OMD, false, + false); ExprValueKind VK = VK_LValue; if (!getLangOptions().CPlusPlus && @@ -4297,7 +4429,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, ExprValueKind VK = VK_LValue; if (Getter) { - PType = Getter->getSendResultType(); + PType = getMessageSendResultType(QualType(OT, 0), Getter, true, + false); if (!getLangOptions().CPlusPlus && IsCForbiddenLValueType(Context, PType)) VK = VK_RValue; @@ -4377,120 +4510,52 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, // If the user is trying to apply -> or . to a function name, it's probably // because they forgot parentheses to call that function. - bool TryCall = false; - bool Overloaded = false; - UnresolvedSet<8> AllOverloads; - if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(BaseExpr.get())) { - AllOverloads.append(Overloads->decls_begin(), Overloads->decls_end()); - TryCall = true; - Overloaded = true; - } else if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(BaseExpr.get())) { - if (FunctionDecl* Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) { - AllOverloads.addDecl(Fun); - TryCall = true; - } - } - - if (TryCall) { - // Plunder the overload set for something that would make the member - // expression valid. - UnresolvedSet<4> ViableOverloads; - bool HasViableZeroArgOverload = false; - for (OverloadExpr::decls_iterator it = AllOverloads.begin(), - DeclsEnd = AllOverloads.end(); it != DeclsEnd; ++it) { - // Our overload set may include TemplateDecls, which we'll ignore for the - // purposes of determining whether we can issue a '()' fixit. - if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>(*it)) { - QualType ResultTy = OverloadDecl->getResultType(); - if ((!IsArrow && ResultTy->isRecordType()) || - (IsArrow && ResultTy->isPointerType() && - ResultTy->getPointeeType()->isRecordType())) { - ViableOverloads.addDecl(*it); - if (OverloadDecl->getMinRequiredArguments() == 0) { - HasViableZeroArgOverload = true; - } - } - } - } - - if (!HasViableZeroArgOverload || ViableOverloads.size() != 1) { + QualType ZeroArgCallTy; + UnresolvedSet<4> Overloads; + if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) { + if (ZeroArgCallTy.isNull()) { Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) - << (AllOverloads.size() > 1) << 0 - << BaseExpr.get()->getSourceRange(); - int ViableOverloadCount = ViableOverloads.size(); - int I; - for (I = 0; I < ViableOverloadCount; ++I) { - // FIXME: Magic number for max shown overloads stolen from - // OverloadCandidateSet::NoteCandidates. - if (I >= 4 && Diags.getShowOverloads() == Diagnostic::Ovl_Best) { - break; - } - Diag(ViableOverloads[I].getDecl()->getSourceRange().getBegin(), - diag::note_member_ref_possible_intended_overload); - } - if (I != ViableOverloadCount) { - Diag(BaseExpr.get()->getExprLoc(), diag::note_ovl_too_many_candidates) - << int(ViableOverloadCount - I); + << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange(); + UnresolvedSet<2> PlausibleOverloads; + for (OverloadExpr::decls_iterator It = Overloads.begin(), + DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) { + const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It); + QualType OverloadResultTy = OverloadDecl->getResultType(); + if ((!IsArrow && OverloadResultTy->isRecordType()) || + (IsArrow && OverloadResultTy->isPointerType() && + OverloadResultTy->getPointeeType()->isRecordType())) + PlausibleOverloads.addDecl(It.getDecl()); } + NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc()); return ExprError(); } - } else { - // We don't have an expression that's convenient to get a Decl from, but we - // can at least check if the type is "function of 0 arguments which returns - // an acceptable type". - const FunctionType *Fun = NULL; - if (const PointerType *Ptr = BaseType->getAs<PointerType>()) { - if ((Fun = Ptr->getPointeeType()->getAs<FunctionType>())) { - TryCall = true; - } - } else if ((Fun = BaseType->getAs<FunctionType>())) { - TryCall = true; - } else if (BaseType == Context.BoundMemberTy) { - // Look for the bound-member type. If it's still overloaded, - // give up, although we probably should have fallen into the - // OverloadExpr case above if we actually have an overloaded - // bound member. - QualType fnType = Expr::findBoundMemberType(BaseExpr.get()); - if (!fnType.isNull()) { - TryCall = true; - Fun = fnType->castAs<FunctionType>(); - } - } - - if (TryCall) { - if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Fun)) { - if (FPT->getNumArgs() == 0) { - QualType ResultTy = Fun->getResultType(); - TryCall = (!IsArrow && ResultTy->isRecordType()) || - (IsArrow && ResultTy->isPointerType() && - ResultTy->getPointeeType()->isRecordType()); - } - } + if ((!IsArrow && ZeroArgCallTy->isRecordType()) || + (IsArrow && ZeroArgCallTy->isPointerType() && + ZeroArgCallTy->getPointeeType()->isRecordType())) { + // At this point, we know BaseExpr looks like it's potentially callable + // with 0 arguments, and that it returns something of a reasonable type, + // so we can emit a fixit and carry on pretending that BaseExpr was + // actually a CallExpr. + SourceLocation ParenInsertionLoc = + PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd()); + Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) + << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange() + << FixItHint::CreateInsertion(ParenInsertionLoc, "()"); + // FIXME: Try this before emitting the fixit, and suppress diagnostics + // while doing so. + ExprResult NewBase = + ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc, + MultiExprArg(*this, 0, 0), + ParenInsertionLoc.getFileLocWithOffset(1)); + if (NewBase.isInvalid()) + return ExprError(); + BaseExpr = NewBase; + BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); } } - if (TryCall) { - // At this point, we know BaseExpr looks like it's potentially callable with - // 0 arguments, and that it returns something of a reasonable type, so we - // can emit a fixit and carry on pretending that BaseExpr was actually a - // CallExpr. - SourceLocation ParenInsertionLoc = - PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd()); - Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) - << int(Overloaded) << 1 - << BaseExpr.get()->getSourceRange() - << FixItHint::CreateInsertion(ParenInsertionLoc, "()"); - ExprResult NewBase = ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc, - MultiExprArg(*this, 0, 0), - ParenInsertionLoc); - if (NewBase.isInvalid()) - return ExprError(); - BaseExpr = NewBase; - BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - } - Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) << BaseType << BaseExpr.get()->getSourceRange(); @@ -4946,6 +5011,26 @@ Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, return ActOnCallExpr(S, ConfigDR, LLLLoc, execConfig, GGGLoc, 0); } +/// ActOnAsTypeExpr - create a new asType (bitcast) from the arguments. +/// +/// __builtin_astype( value, dst type ) +/// +ExprResult Sema::ActOnAsTypeExpr(Expr *expr, ParsedType destty, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc) { + ExprValueKind VK = VK_RValue; + ExprObjectKind OK = OK_Ordinary; + QualType DstTy = GetTypeFromParser(destty); + QualType SrcTy = expr->getType(); + if (Context.getTypeSize(DstTy) != Context.getTypeSize(SrcTy)) + return ExprError(Diag(BuiltinLoc, + diag::err_invalid_astype_of_different_size) + << DstTy + << SrcTy + << expr->getSourceRange()); + return Owned(new (Context) AsTypeExpr(expr, DstTy, VK, OK, BuiltinLoc, RParenLoc)); +} + /// BuildResolvedCallExpr - Build a call to a resolved expression, /// i.e. an expression not of \p OverloadTy. The expression should /// unary-convert to an expression of function-pointer or @@ -6118,6 +6203,150 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, return QualType(); } +/// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps +/// ParenRange in parentheses. +static void SuggestParentheses(Sema &Self, SourceLocation Loc, + const PartialDiagnostic &PD, + const PartialDiagnostic &FirstNote, + SourceRange FirstParenRange, + const PartialDiagnostic &SecondNote, + SourceRange SecondParenRange) { + Self.Diag(Loc, PD); + + if (!FirstNote.getDiagID()) + return; + + SourceLocation EndLoc = Self.PP.getLocForEndOfToken(FirstParenRange.getEnd()); + if (!FirstParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { + // We can't display the parentheses, so just return. + return; + } + + Self.Diag(Loc, FirstNote) + << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(") + << FixItHint::CreateInsertion(EndLoc, ")"); + + if (!SecondNote.getDiagID()) + return; + + EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd()); + if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { + // We can't display the parentheses, so just dig the + // warning/error and return. + Self.Diag(Loc, SecondNote); + return; + } + + Self.Diag(Loc, SecondNote) + << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(") + << FixItHint::CreateInsertion(EndLoc, ")"); +} + +static bool IsArithmeticOp(BinaryOperatorKind Opc) { + return Opc >= BO_Mul && Opc <= BO_Shr; +} + +/// IsArithmeticBinaryExpr - Returns true if E is an arithmetic binary +/// expression, either using a built-in or overloaded operator, +/// and sets *OpCode to the opcode and *RHS to the right-hand side expression. +static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode, + Expr **RHS) { + E = E->IgnoreParenImpCasts(); + E = E->IgnoreConversionOperator(); + E = E->IgnoreParenImpCasts(); + + // Built-in binary operator. + if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E)) { + if (IsArithmeticOp(OP->getOpcode())) { + *Opcode = OP->getOpcode(); + *RHS = OP->getRHS(); + return true; + } + } + + // Overloaded operator. + if (CXXOperatorCallExpr *Call = dyn_cast<CXXOperatorCallExpr>(E)) { + if (Call->getNumArgs() != 2) + return false; + + // Make sure this is really a binary operator that is safe to pass into + // BinaryOperator::getOverloadedOpcode(), e.g. it's not a subscript op. + OverloadedOperatorKind OO = Call->getOperator(); + if (OO < OO_Plus || OO > OO_Arrow) + return false; + + BinaryOperatorKind OpKind = BinaryOperator::getOverloadedOpcode(OO); + if (IsArithmeticOp(OpKind)) { + *Opcode = OpKind; + *RHS = Call->getArg(1); + return true; + } + } + + return false; +} + +static bool IsLogicOp(BinaryOperatorKind Opc) { + return (Opc >= BO_LT && Opc <= BO_NE) || (Opc >= BO_LAnd && Opc <= BO_LOr); +} + +/// ExprLooksBoolean - Returns true if E looks boolean, i.e. it has boolean type +/// or is a logical expression such as (x==y) which has int type, but is +/// commonly interpreted as boolean. +static bool ExprLooksBoolean(Expr *E) { + E = E->IgnoreParenImpCasts(); + + if (E->getType()->isBooleanType()) + return true; + if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E)) + return IsLogicOp(OP->getOpcode()); + if (UnaryOperator *OP = dyn_cast<UnaryOperator>(E)) + return OP->getOpcode() == UO_LNot; + + return false; +} + +/// DiagnoseConditionalPrecedence - Emit a warning when a conditional operator +/// and binary operator are mixed in a way that suggests the programmer assumed +/// the conditional operator has higher precedence, for example: +/// "int x = a + someBinaryCondition ? 1 : 2". +static void DiagnoseConditionalPrecedence(Sema &Self, + SourceLocation OpLoc, + Expr *cond, + Expr *lhs, + Expr *rhs) { + BinaryOperatorKind CondOpcode; + Expr *CondRHS; + + if (!IsArithmeticBinaryExpr(cond, &CondOpcode, &CondRHS)) + return; + if (!ExprLooksBoolean(CondRHS)) + return; + + // The condition is an arithmetic binary expression, with a right- + // hand side that looks boolean, so warn. + + PartialDiagnostic Warn = Self.PDiag(diag::warn_precedence_conditional) + << cond->getSourceRange() + << BinaryOperator::getOpcodeStr(CondOpcode); + + PartialDiagnostic FirstNote = + Self.PDiag(diag::note_precedence_conditional_silence) + << BinaryOperator::getOpcodeStr(CondOpcode); + + SourceRange FirstParenRange(cond->getLocStart(), + cond->getLocEnd()); + + PartialDiagnostic SecondNote = + Self.PDiag(diag::note_precedence_conditional_first); + + SourceRange SecondParenRange(CondRHS->getLocStart(), + rhs->getLocEnd()); + + SuggestParentheses(Self, OpLoc, Warn, FirstNote, FirstParenRange, + SecondNote, SecondParenRange); +} + /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null /// in the case of a the GNU conditional expr extension. ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, @@ -6162,6 +6391,9 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, RHS.isInvalid()) return ExprError(); + DiagnoseConditionalPrecedence(*this, QuestionLoc, Cond.get(), LHS.get(), + RHS.get()); + if (!commonExpr) return Owned(new (Context) ConditionalOperator(Cond.take(), QuestionLoc, LHS.take(), ColonLoc, @@ -7487,7 +7719,7 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca // Comparison of pointers with null pointer constants and equality // comparisons of member pointers to null pointer constants. if (RHSIsNull && - ((lType->isPointerType() || lType->isNullPtrType()) || + ((lType->isAnyPointerType() || lType->isNullPtrType()) || (!isRelational && lType->isMemberPointerType()))) { rex = ImpCastExprToType(rex.take(), lType, lType->isMemberPointerType() @@ -7496,7 +7728,7 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca return ResultTy; } if (LHSIsNull && - ((rType->isPointerType() || rType->isNullPtrType()) || + ((rType->isAnyPointerType() || rType->isNullPtrType()) || (!isRelational && rType->isMemberPointerType()))) { lex = ImpCastExprToType(lex.take(), rType, rType->isMemberPointerType() @@ -7748,13 +7980,15 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] // If the RHS can be constant folded, and if it constant folds to something // that isn't 0 or 1 (which indicate a potential logical operation that // happened to fold to true/false) then warn. + // Parens on the RHS are ignored. Expr::EvalResult Result; - if (rex.get()->Evaluate(Result, Context) && !Result.HasSideEffects && - Result.Val.getInt() != 0 && Result.Val.getInt() != 1) { - Diag(Loc, diag::warn_logical_instead_of_bitwise) - << rex.get()->getSourceRange() - << (Opc == BO_LAnd ? "&&" : "||") - << (Opc == BO_LAnd ? "&" : "|"); + if (rex.get()->Evaluate(Result, Context) && !Result.HasSideEffects) + if ((getLangOptions().Bool && !rex.get()->getType()->isBooleanType()) || + (Result.Val.getInt() != 0 && Result.Val.getInt() != 1)) { + Diag(Loc, diag::warn_logical_instead_of_bitwise) + << rex.get()->getSourceRange() + << (Opc == BO_LAnd ? "&&" : "||") + << (Opc == BO_LAnd ? "&" : "|"); } } @@ -8127,20 +8361,31 @@ ExprResult Sema::ConvertPropertyForRValue(Expr *E) { E->getObjectKind() == OK_ObjCProperty); const ObjCPropertyRefExpr *PRE = E->getObjCProperty(); + QualType T = E->getType(); + QualType ReceiverType; + if (PRE->isObjectReceiver()) + ReceiverType = PRE->getBase()->getType(); + else if (PRE->isSuperReceiver()) + ReceiverType = PRE->getSuperReceiverType(); + else + ReceiverType = Context.getObjCInterfaceType(PRE->getClassReceiver()); + ExprValueKind VK = VK_RValue; if (PRE->isImplicitProperty()) { - if (const ObjCMethodDecl *GetterMethod = + if (ObjCMethodDecl *GetterMethod = PRE->getImplicitPropertyGetter()) { - QualType Result = GetterMethod->getResultType(); - VK = Expr::getValueKindForType(Result); + T = getMessageSendResultType(ReceiverType, GetterMethod, + PRE->isClassReceiver(), + PRE->isSuperReceiver()); + VK = Expr::getValueKindForType(GetterMethod->getResultType()); } else { Diag(PRE->getLocation(), diag::err_getter_not_found) << PRE->getBase()->getType(); } } - - E = ImplicitCastExpr::Create(Context, E->getType(), CK_GetObjCProperty, + + E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty, E, 0, VK); ExprResult Result = MaybeBindToTemporary(E); @@ -8404,7 +8649,13 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, Op = ConvResult.take(); QualType OpTy = Op->getType(); QualType Result; - + + if (isa<CXXReinterpretCastExpr>(Op)) { + QualType OpOrigType = Op->IgnoreParenCasts()->getType(); + S.CheckCompatibleReinterpretCast(OpOrigType, OpTy, /*IsDereference*/true, + Op->getSourceRange()); + } + // Note that per both C89 and C99, indirection is always legal, even if OpTy // is an incomplete type or void. It would be possible to warn about // dereferencing a void pointer, but it's completely well-defined, and such a @@ -8678,45 +8929,6 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, CompResultTy, OpLoc)); } -/// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps -/// ParenRange in parentheses. -static void SuggestParentheses(Sema &Self, SourceLocation Loc, - const PartialDiagnostic &PD, - const PartialDiagnostic &FirstNote, - SourceRange FirstParenRange, - const PartialDiagnostic &SecondNote, - SourceRange SecondParenRange) { - Self.Diag(Loc, PD); - - if (!FirstNote.getDiagID()) - return; - - SourceLocation EndLoc = Self.PP.getLocForEndOfToken(FirstParenRange.getEnd()); - if (!FirstParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { - // We can't display the parentheses, so just return. - return; - } - - Self.Diag(Loc, FirstNote) - << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(") - << FixItHint::CreateInsertion(EndLoc, ")"); - - if (!SecondNote.getDiagID()) - return; - - EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd()); - if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { - // We can't display the parentheses, so just dig the - // warning/error and return. - Self.Diag(Loc, SecondNote); - return; - } - - Self.Diag(Loc, SecondNote) - << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(") - << FixItHint::CreateInsertion(EndLoc, ")"); -} - /// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison /// operators are mixed in a way that suggests that the programmer forgot that /// comparison operators have higher precedence. The most typical example of @@ -9666,6 +9878,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, *Complained = false; // Decode the result (notice that AST's are still created for extensions). + bool CheckInferredResultType = false; bool isInvalid = false; unsigned DiagKind; FixItHint Hint; @@ -9682,6 +9895,8 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, case IncompatiblePointer: MakeObjCStringLiteralFixItHint(*this, DstType, SrcExpr, Hint); DiagKind = diag::ext_typecheck_convert_incompatible_pointer; + CheckInferredResultType = DstType->isObjCObjectPointerType() && + SrcType->isObjCObjectPointerType(); break; case IncompatiblePointerSign: DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign; @@ -9763,6 +9978,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, Diag(Loc, DiagKind) << FirstType << SecondType << Action << SrcExpr->getSourceRange() << Hint; + if (CheckInferredResultType) + EmitRelatedResultTypeNote(SrcExpr); + if (Complained) *Complained = true; return isInvalid; @@ -9914,26 +10132,25 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // Note that this declaration has been used. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { - unsigned TypeQuals; - if (Constructor->isImplicit() && Constructor->isDefaultConstructor()) { - if (Constructor->getParent()->hasTrivialConstructor()) + if (Constructor->isDefaulted() && Constructor->isDefaultConstructor()) { + if (Constructor->isTrivial()) return; if (!Constructor->isUsed(false)) DefineImplicitDefaultConstructor(Loc, Constructor); - } else if (Constructor->isImplicit() && - Constructor->isCopyConstructor(TypeQuals)) { + } else if (Constructor->isDefaulted() && + Constructor->isCopyConstructor()) { if (!Constructor->isUsed(false)) - DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals); + DefineImplicitCopyConstructor(Loc, Constructor); } MarkVTableUsed(Loc, Constructor->getParent()); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { - if (Destructor->isImplicit() && !Destructor->isUsed(false)) + if (Destructor->isDefaulted() && !Destructor->isUsed(false)) DefineImplicitDestructor(Loc, Destructor); if (Destructor->isVirtual()) MarkVTableUsed(Loc, Destructor->getParent()); } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) { - if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() && + if (MethodDecl->isDefaulted() && MethodDecl->isOverloadedOperator() && MethodDecl->getOverloadedOperator() == OO_Equal) { if (!MethodDecl->isUsed(false)) DefineImplicitCopyAssignment(Loc, MethodDecl); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 7f1bf59..2f5a890 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -17,6 +17,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/Scope.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -385,13 +386,14 @@ static UuidAttr *GetUuidAttrOfType(QualType QT) { else if (QT->isArrayType()) Ty = cast<ArrayType>(QT)->getElementType().getTypePtr(); - // Loop all class definition and declaration looking for an uuid attribute. + // Loop all record redeclaration looking for an uuid attribute. CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); - while (RD) { - if (UuidAttr *Uuid = RD->getAttr<UuidAttr>()) + for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(), + E = RD->redecls_end(); I != E; ++I) { + if (UuidAttr *Uuid = I->getAttr<UuidAttr>()) return Uuid; - RD = RD->getPreviousDeclaration(); } + return 0; } @@ -574,42 +576,54 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E) { return Owned(E); } -CXXMethodDecl *Sema::tryCaptureCXXThis() { +QualType Sema::getAndCaptureCurrentThisType() { // Ignore block scopes: we can capture through them. // Ignore nested enum scopes: we'll diagnose non-constant expressions // where they're invalid, and other uses are legitimate. // Don't ignore nested class scopes: you can't use 'this' in a local class. DeclContext *DC = CurContext; + unsigned NumBlocks = 0; while (true) { - if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext(); - else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext(); + if (isa<BlockDecl>(DC)) { + DC = cast<BlockDecl>(DC)->getDeclContext(); + ++NumBlocks; + } else if (isa<EnumDecl>(DC)) + DC = cast<EnumDecl>(DC)->getDeclContext(); else break; } - // If we're not in an instance method, error out. - CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC); - if (!method || !method->isInstance()) - return 0; + QualType ThisTy; + 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)); + } - // Mark that we're closing on 'this' in all the block scopes, if applicable. - for (unsigned idx = FunctionScopes.size() - 1; - isa<BlockScopeInfo>(FunctionScopes[idx]); - --idx) - cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true; + // Mark that we're closing on 'this' in all the block scopes we ignored. + if (!ThisTy.isNull()) + for (unsigned idx = FunctionScopes.size() - 1; + NumBlocks; --idx, --NumBlocks) + cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true; - return method; + return ThisTy; } -ExprResult Sema::ActOnCXXThis(SourceLocation loc) { +ExprResult Sema::ActOnCXXThis(SourceLocation Loc) { /// C++ 9.3.2: In the body of a non-static member function, the keyword this /// is a non-lvalue expression whose value is the address of the object for /// which the function is called. - CXXMethodDecl *method = tryCaptureCXXThis(); - if (!method) return Diag(loc, diag::err_invalid_this_use); + QualType ThisTy = getAndCaptureCurrentThisType(); + if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use); - return Owned(new (Context) CXXThisExpr(loc, method->getThisType(Context), - /*isImplicit=*/false)); + return Owned(new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false)); } ExprResult @@ -950,8 +964,8 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, } } - ArraySize = ImpCastExprToType(ArraySize, Context.getSizeType(), - CK_IntegralCast).take(); + // Note that we do *not* convert the argument in any way. It can + // be signed, larger than size_t, whatever. } FunctionDecl *OperatorNew = 0; @@ -1326,11 +1340,12 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, DeclarationName Name, Expr** Args, unsigned NumArgs, DeclContext *Ctx, - bool AllowMissing, FunctionDecl *&Operator) { + bool AllowMissing, FunctionDecl *&Operator, + bool Diagnose) { LookupResult R(*this, Name, StartLoc, LookupOrdinaryName); LookupQualifiedName(R, Ctx); if (R.empty()) { - if (AllowMissing) + if (AllowMissing || !Diagnose) return false; return Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) << Name << Range; @@ -1374,41 +1389,50 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, // Watch out for variadic allocator function. unsigned NumArgsInFnDecl = FnDecl->getNumParams(); for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) { + InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, + FnDecl->getParamDecl(i)); + + if (!Diagnose && !CanPerformCopyInitialization(Entity, Owned(Args[i]))) + return true; + ExprResult Result - = PerformCopyInitialization(InitializedEntity::InitializeParameter( - Context, - FnDecl->getParamDecl(i)), - SourceLocation(), - Owned(Args[i])); + = PerformCopyInitialization(Entity, SourceLocation(), Owned(Args[i])); if (Result.isInvalid()) return true; Args[i] = Result.takeAs<Expr>(); } Operator = FnDecl; - CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl); + CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl, + Diagnose); return false; } case OR_No_Viable_Function: - Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) - << Name << Range; - Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); + if (Diagnose) { + Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) + << Name << Range; + Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); + } return true; case OR_Ambiguous: - Diag(StartLoc, diag::err_ovl_ambiguous_call) - << Name << Range; - Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs); + if (Diagnose) { + Diag(StartLoc, diag::err_ovl_ambiguous_call) + << Name << Range; + Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs); + } return true; case OR_Deleted: { - Diag(StartLoc, diag::err_ovl_deleted_call) - << Best->Function->isDeleted() - << Name - << getDeletedOrUnavailableSuffix(Best->Function) - << Range; - Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); + if (Diagnose) { + Diag(StartLoc, diag::err_ovl_deleted_call) + << Best->Function->isDeleted() + << Name + << getDeletedOrUnavailableSuffix(Best->Function) + << Range; + Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); + } return true; } } @@ -1568,7 +1592,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, - FunctionDecl* &Operator) { + FunctionDecl* &Operator, bool Diagnose) { LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName); // Try to find operator delete/operator delete[] in class scope. LookupQualifiedName(Found, RD); @@ -1595,33 +1619,45 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, // There's exactly one suitable operator; pick it. if (Matches.size() == 1) { Operator = cast<CXXMethodDecl>(Matches[0]->getUnderlyingDecl()); + + if (Operator->isDeleted()) { + if (Diagnose) { + Diag(StartLoc, diag::err_deleted_function_use); + Diag(Operator->getLocation(), diag::note_unavailable_here) << true; + } + return true; + } + CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(), - Matches[0]); + Matches[0], Diagnose); return false; // We found multiple suitable operators; complain about the ambiguity. } else if (!Matches.empty()) { - Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found) - << Name << RD; - - for (llvm::SmallVectorImpl<DeclAccessPair>::iterator - F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F) - Diag((*F)->getUnderlyingDecl()->getLocation(), - diag::note_member_declared_here) << Name; + if (Diagnose) { + Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found) + << Name << RD; + + for (llvm::SmallVectorImpl<DeclAccessPair>::iterator + F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F) + Diag((*F)->getUnderlyingDecl()->getLocation(), + diag::note_member_declared_here) << Name; + } return true; } // We did find operator delete/operator delete[] declarations, but // none of them were suitable. if (!Found.empty()) { - Diag(StartLoc, diag::err_no_suitable_delete_member_function_found) - << Name << RD; - - for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); - F != FEnd; ++F) - Diag((*F)->getUnderlyingDecl()->getLocation(), - diag::note_member_declared_here) << Name; - + if (Diagnose) { + Diag(StartLoc, diag::err_no_suitable_delete_member_function_found) + << Name << RD; + + for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); + F != FEnd; ++F) + Diag((*F)->getUnderlyingDecl()->getLocation(), + diag::note_member_declared_here) << Name; + } return true; } @@ -1633,8 +1669,8 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, Expr* DeallocArgs[1]; DeallocArgs[0] = &Null; if (FindAllocationOverload(StartLoc, SourceRange(), Name, - DeallocArgs, 1, TUDecl, /*AllowMissing=*/false, - Operator)) + DeallocArgs, 1, TUDecl, !Diagnose, + Operator, Diagnose)) return true; assert(Operator && "Did not find a deallocation function!"); @@ -1780,6 +1816,20 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, const_cast<CXXDestructorDecl*>(Dtor)); DiagnoseUseOfDecl(Dtor, StartLoc); } + + // C++ [expr.delete]p3: + // In the first alternative (delete object), if the static type of the + // object to be deleted is different from its dynamic type, the static + // type shall be a base class of the dynamic type of the object to be + // deleted and the static type shall have a virtual destructor or the + // behavior is undefined. + // + // Note: a final class cannot be derived from, no issue there + if (!ArrayForm && RD->isPolymorphic() && !RD->hasAttr<FinalAttr>()) { + CXXDestructorDecl *dtor = RD->getDestructor(); + if (!dtor || !dtor->isVirtual()) + Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem; + } } if (!OperatorDelete) { @@ -2174,7 +2224,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, case ICK_Pointer_Conversion: { if (SCS.IncompatibleObjC && Action != AA_Casting) { // Diagnose incompatible Objective-C conversions - if (Action == AA_Initializing) + if (Action == AA_Initializing || Action == AA_Assigning) Diag(From->getSourceRange().getBegin(), diag::ext_typecheck_convert_incompatible_pointer) << ToType << From->getType() << Action @@ -2184,6 +2234,10 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, diag::ext_typecheck_convert_incompatible_pointer) << From->getType() << ToType << Action << From->getSourceRange(); + + if (From->getType()->isObjCObjectPointerType() && + ToType->isObjCObjectPointerType()) + EmitRelatedResultTypeNote(From); } CastKind Kind = CK_Invalid; @@ -2416,6 +2470,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, // C++0x [meta.unary.prop] Table 49 requires the following traits to be // applied to a complete type. case UTT_IsTrivial: + case UTT_IsTriviallyCopyable: case UTT_IsStandardLayout: case UTT_IsPOD: case UTT_IsLiteral: @@ -2433,7 +2488,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, case UTT_HasNothrowConstructor: case UTT_HasNothrowCopy: case UTT_HasTrivialAssign: - case UTT_HasTrivialConstructor: + case UTT_HasTrivialDefaultConstructor: case UTT_HasTrivialCopy: case UTT_HasTrivialDestructor: case UTT_HasVirtualDestructor: @@ -2512,6 +2567,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, return T.isVolatileQualified(); case UTT_IsTrivial: return T->isTrivialType(); + case UTT_IsTriviallyCopyable: + return T->isTriviallyCopyableType(); case UTT_IsStandardLayout: return T->isStandardLayoutType(); case UTT_IsPOD: @@ -2543,7 +2600,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, // // 1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html // 2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index - case UTT_HasTrivialConstructor: + case UTT_HasTrivialDefaultConstructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If __is_pod (type) is true then the trait is true, else if type is // a cv class or union type (or array thereof) with a trivial default @@ -2552,7 +2609,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, return true; if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) - return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialConstructor(); + return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDefaultConstructor(); return false; case UTT_HasTrivialCopy: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: @@ -2619,7 +2676,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, return true; bool FoundAssign = false; - bool AllNoThrow = true; DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal); LookupResult Res(Self, DeclarationNameInfo(Name, KeyLoc), Sema::LookupOrdinaryName); @@ -2631,15 +2687,15 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, FoundAssign = true; const FunctionProtoType *CPT = Operator->getType()->getAs<FunctionProtoType>(); - if (!CPT->isNothrow(Self.Context)) { - AllNoThrow = false; - break; - } + if (CPT->getExceptionSpecType() == EST_Delayed) + return false; + if (!CPT->isNothrow(Self.Context)) + return false; } } } - return FoundAssign && AllNoThrow; + return FoundAssign; } return false; case UTT_HasNothrowCopy: @@ -2656,7 +2712,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, return true; bool FoundConstructor = false; - bool AllNoThrow = true; unsigned FoundTQs; DeclContext::lookup_const_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD); @@ -2671,16 +2726,16 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, FoundConstructor = true; const FunctionProtoType *CPT = Constructor->getType()->getAs<FunctionProtoType>(); + if (CPT->getExceptionSpecType() == EST_Delayed) + return false; // FIXME: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. - if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1) { - AllNoThrow = false; - break; - } + if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1) + return false; } } - return FoundConstructor && AllNoThrow; + return FoundConstructor; } return false; case UTT_HasNothrowConstructor: @@ -2693,7 +2748,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, return true; if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (RD->hasTrivialConstructor()) + if (RD->hasTrivialDefaultConstructor()) return true; DeclContext::lookup_const_iterator Con, ConEnd; @@ -2706,6 +2761,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, if (Constructor->isDefaultConstructor()) { const FunctionProtoType *CPT = Constructor->getType()->getAs<FunctionProtoType>(); + if (CPT->getExceptionSpecType() == EST_Delayed) + return false; // TODO: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0; @@ -2852,7 +2909,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT, Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); InitializationSequence Init(Self, To, Kind, &FromPtr, 1); - if (Init.getKind() == InitializationSequence::FailedSequence) + if (Init.Failed()) return false; ExprResult Result = Init.Perform(Self, To, Kind, MultiExprArg(&FromPtr, 1)); @@ -3213,7 +3270,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, if (TTy.isAtLeastAsQualifiedAs(FTy)) { InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); - if (InitSeq.getKind() != InitializationSequence::FailedSequence) { + if (InitSeq) { HaveConversion = true; return false; } @@ -3238,7 +3295,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); - HaveConversion = InitSeq.getKind() != InitializationSequence::FailedSequence; + HaveConversion = !InitSeq.Failed(); ToType = TTy; if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); @@ -4295,3 +4352,18 @@ StmtResult Sema::ActOnFinishFullStmt(Stmt *FullStmt) { return MaybeCreateStmtWithCleanups(FullStmt); } + +bool Sema::CheckMicrosoftIfExistsSymbol(CXXScopeSpec &SS, + UnqualifiedId &Name) { + DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name); + DeclarationName TargetName = TargetNameInfo.getName(); + if (!TargetName) + return false; + + // Do the redeclaration lookup in the current scope. + LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName, + Sema::NotForRedeclaration); + R.suppressDiagnostics(); + LookupParsedName(R, getCurScope(), &SS); + return !R.empty(); +} diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 2a262f0..cb5c1e0 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -119,7 +119,7 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, return new (Context) ObjCStringLiteral(S, Ty, AtLocs[0]); } -Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, +ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, TypeSourceInfo *EncodedTypeInfo, SourceLocation RParenLoc) { QualType EncodedType = EncodedTypeInfo->getType(); @@ -127,6 +127,12 @@ Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, if (EncodedType->isDependentType()) StrTy = Context.DependentTy; else { + if (!EncodedType->getAsArrayTypeUnsafe()) // Incomplete array is handled. + if (RequireCompleteType(AtLoc, EncodedType, + PDiag(diag::err_incomplete_type_objc_at_encode) + << EncodedTypeInfo->getTypeLoc().getSourceRange())) + return ExprError(); + std::string Str; Context.getObjCEncodingForType(EncodedType, Str); @@ -235,10 +241,72 @@ ObjCMethodDecl *Sema::tryCaptureObjCSelf() { return method; } +QualType Sema::getMessageSendResultType(QualType ReceiverType, + ObjCMethodDecl *Method, + bool isClassMessage, bool isSuperMessage) { + assert(Method && "Must have a method"); + if (!Method->hasRelatedResultType()) + return Method->getSendResultType(); + + // If a method has a related return type: + // - if the method found is an instance method, but the message send + // was a class message send, T is the declared return type of the method + // found + if (Method->isInstanceMethod() && isClassMessage) + return Method->getSendResultType(); + + // - if the receiver is super, T is a pointer to the class of the + // enclosing method definition + if (isSuperMessage) { + if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) + if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface()) + return Context.getObjCObjectPointerType( + Context.getObjCInterfaceType(Class)); + } + + // - if the receiver is the name of a class U, T is a pointer to U + if (ReceiverType->getAs<ObjCInterfaceType>() || + ReceiverType->isObjCQualifiedInterfaceType()) + return Context.getObjCObjectPointerType(ReceiverType); + // - if the receiver is of type Class or qualified Class type, + // T is the declared return type of the method. + if (ReceiverType->isObjCClassType() || + ReceiverType->isObjCQualifiedClassType()) + return Method->getSendResultType(); + + // - if the receiver is id, qualified id, Class, or qualified Class, T + // is the receiver type, otherwise + // - T is the type of the receiver expression. + return ReceiverType; +} + +void Sema::EmitRelatedResultTypeNote(const Expr *E) { + E = E->IgnoreParenImpCasts(); + const ObjCMessageExpr *MsgSend = dyn_cast<ObjCMessageExpr>(E); + if (!MsgSend) + return; + + const ObjCMethodDecl *Method = MsgSend->getMethodDecl(); + if (!Method) + return; + + if (!Method->hasRelatedResultType()) + return; + + if (Context.hasSameUnqualifiedType(Method->getResultType() + .getNonReferenceType(), + MsgSend->getType())) + return; + + Diag(Method->getLocation(), diag::note_related_result_type_inferred) + << Method->isInstanceMethod() << Method->getSelector() + << MsgSend->getType(); +} -bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, +bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, + Expr **Args, unsigned NumArgs, Selector Sel, ObjCMethodDecl *Method, - bool isClassMessage, + bool isClassMessage, bool isSuperMessage, SourceLocation lbrac, SourceLocation rbrac, QualType &ReturnType, ExprValueKind &VK) { if (!Method) { @@ -262,7 +330,8 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, return false; } - ReturnType = Method->getSendResultType(); + ReturnType = getMessageSendResultType(ReceiverType, Method, isClassMessage, + isSuperMessage); VK = Expr::getValueKindForType(Method->getResultType()); unsigned NumNamedArgs = Sel.getNumArgs(); @@ -450,9 +519,12 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, ResTy = ResTy.getNonLValueExprType(Context); Selector Sel = PP.getSelectorTable().getNullarySelector(Member); ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); - if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)) - ResTy = Getter->getResultType(); - + if (Getter && + (Getter->hasRelatedResultType() + || DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))) + ResTy = getMessageSendResultType(QualType(OPT, 0), Getter, false, + Super); + if (Super) return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, VK_LValue, OK_ObjCProperty, @@ -470,14 +542,18 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); + + QualType T = PD->getType(); + if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + T = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super); if (Super) - return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + return Owned(new (Context) ObjCPropertyRefExpr(PD, T, VK_LValue, OK_ObjCProperty, MemberLoc, SuperLoc, SuperType)); else - return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + return Owned(new (Context) ObjCPropertyRefExpr(PD, T, VK_LValue, OK_ObjCProperty, MemberLoc, @@ -534,7 +610,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, if (Getter || Setter) { QualType PType; if (Getter) - PType = Getter->getSendResultType(); + PType = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super); else { ParmVarDecl *ArgDecl = *Setter->param_begin(); PType = ArgDecl->getType(); @@ -608,10 +684,14 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, IdentifierInfo *receiverNamePtr = &receiverName; ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr, receiverNameLoc); + + bool IsSuper = false; if (IFace == 0) { // If the "receiver" is 'super' in a method, handle it as an expression-like // property reference. if (receiverNamePtr->isStr("super")) { + IsSuper = true; + if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf()) { if (CurMethod->isInstanceMethod()) { QualType T = @@ -680,7 +760,9 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, ExprValueKind VK = VK_LValue; if (Getter) { - PType = Getter->getSendResultType(); + PType = getMessageSendResultType(Context.getObjCInterfaceType(IFace), + Getter, true, + receiverNamePtr->isStr("super")); if (!getLangOptions().CPlusPlus && !PType.hasQualifiers() && PType->isVoidType()) VK = VK_RValue; @@ -693,6 +775,13 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty); + if (IsSuper) + return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, + PType, VK, OK, + propertyNameLoc, + receiverNameLoc, + Context.getObjCInterfaceType(IFace))); + return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, PType, VK, OK, propertyNameLoc, @@ -949,8 +1038,9 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, unsigned NumArgs = ArgsIn.size(); Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); - if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, true, - LBracLoc, RBracLoc, ReturnType, VK)) + if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, Method, true, + SuperLoc.isValid(), LBracLoc, RBracLoc, + ReturnType, VK)) return ExprError(); if (Method && !Method->getResultType()->isVoidType() && @@ -1232,7 +1322,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, ExprValueKind VK = VK_RValue; bool ClassMessage = (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()); - if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, ClassMessage, + if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, Method, + ClassMessage, SuperLoc.isValid(), LBracLoc, RBracLoc, ReturnType, VK)) return ExprError(); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index ca3fd6d..a33f5d0 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -296,8 +296,7 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, // Do nothing } else if (Init < NumInits) { ILE->setInit(Init, MemberInit.takeAs<Expr>()); - } else if (InitSeq.getKind() - == InitializationSequence::ConstructorInitialization) { + } else if (InitSeq.isConstructorInitialization()) { // Value-initialization requires a constructor call, so // extend the initializer list to include the constructor // call and make a note that we'll need to take another pass @@ -418,8 +417,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, return; } - if (InitSeq.getKind() - == InitializationSequence::ConstructorInitialization) { + if (InitSeq.isConstructorInitialization()) { // Value-initialization requires a constructor call, so // extend the initializer list to include the constructor // call and make a note that we'll need to take another pass @@ -2137,7 +2135,7 @@ bool InitializationSequence::isDirectReferenceBinding() const { } bool InitializationSequence::isAmbiguous() const { - if (getKind() != FailedSequence) + if (!Failed()) return false; switch (getFailureKind()) { @@ -2310,7 +2308,7 @@ void InitializationSequence::AddArrayInitStep(QualType T) { void InitializationSequence::SetOverloadFailure(FailureKind Failure, OverloadingResult Result) { - SequenceKind = FailedSequence; + setSequenceKind(FailedSequence); this->Failure = Failure; this->FailedOverloadResult = Result; } @@ -2331,7 +2329,6 @@ static void TryListInitialization(Sema &S, // well-formed. When we actually "perform" list initialization, we'll // do all of the necessary checking. C++0x initializer lists will // force us to perform more checking here. - Sequence.setSequenceKind(InitializationSequence::ListInitialization); QualType DestType = Entity.getType(); @@ -2800,7 +2797,6 @@ static void TryStringLiteralInitialization(Sema &S, const InitializationKind &Kind, Expr *Initializer, InitializationSequence &Sequence) { - Sequence.setSequenceKind(InitializationSequence::StringInit); Sequence.AddStringInitStep(Entity.getType()); } @@ -2813,8 +2809,6 @@ static void TryConstructorInitialization(Sema &S, Expr **Args, unsigned NumArgs, QualType DestType, InitializationSequence &Sequence) { - Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization); - // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); @@ -2947,7 +2941,6 @@ static void TryValueInitialization(Sema &S, } Sequence.AddZeroInitializationStep(Entity.getType()); - Sequence.setSequenceKind(InitializationSequence::ZeroInitialization); } /// \brief Attempt default initialization (C++ [dcl.init]p6). @@ -2973,7 +2966,6 @@ static void TryDefaultInitialization(Sema &S, } // - otherwise, no initialization is performed. - Sequence.setSequenceKind(InitializationSequence::NoInitialization); // If a program calls for the default initialization of an object of // a const-qualified type T, T shall be a class type with a user-provided @@ -2990,8 +2982,6 @@ static void TryUserDefinedConversion(Sema &S, const InitializationKind &Kind, Expr *Initializer, InitializationSequence &Sequence) { - Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion); - QualType DestType = Entity.getType(); assert(!DestType->isReferenceType() && "References are handled elsewhere"); QualType SourceType = Initializer->getType(); @@ -3176,6 +3166,9 @@ InitializationSequence::InitializationSequence(Sema &S, return; } + // Almost everything is a normal sequence. + setSequenceKind(NormalSequence); + for (unsigned I = 0; I != NumArgs; ++I) if (Args[I]->getObjectKind() == OK_ObjCProperty) { ExprResult Result = S.ConvertPropertyForRValue(Args[I]); @@ -3252,7 +3245,6 @@ InitializationSequence::InitializationSequence(Sema &S, else if (Initializer->HasSideEffects(S.Context)) SetFailed(FK_NonConstantArrayInit); else { - setSequenceKind(ArrayInit); AddArrayInitStep(DestType); } } else if (DestAT->getElementType()->isAnyCharacterType()) @@ -3265,7 +3257,6 @@ InitializationSequence::InitializationSequence(Sema &S, // Handle initialization in C if (!S.getLangOptions().CPlusPlus) { - setSequenceKind(CAssignment); AddCAssignmentStep(DestType); return; } @@ -3325,8 +3316,6 @@ InitializationSequence::InitializationSequence(Sema &S, else SetFailed(InitializationSequence::FK_ConversionFailed); } - else - setSequenceKind(StandardConversion); } InitializationSequence::~InitializationSequence() { @@ -3650,13 +3639,13 @@ InitializationSequence::Perform(Sema &S, const InitializationKind &Kind, MultiExprArg Args, QualType *ResultType) { - if (SequenceKind == FailedSequence) { + if (Failed()) { unsigned NumArgs = Args.size(); Diagnose(S, Entity, Kind, (Expr **)Args.release(), NumArgs); return ExprError(); } - if (SequenceKind == DependentSequence) { + if (getKind() == DependentSequence) { // If the declaration is a non-dependent, incomplete array type // that has an initializer, then its type will be completed once // the initializer is instantiated. @@ -3710,7 +3699,8 @@ InitializationSequence::Perform(Sema &S, SourceLocation())); } - if (SequenceKind == NoInitialization) + // No steps means no initialization. + if (Steps.empty()) return S.Owned((Expr *)0); QualType DestType = Entity.getType().getNonReferenceType(); @@ -3723,8 +3713,6 @@ InitializationSequence::Perform(Sema &S, ExprResult CurInit = S.Owned((Expr *)0); - assert(!Steps.empty() && "Cannot have an empty initialization sequence"); - // For initialization steps that start with a single initializer, // grab the only argument out the Args and place it into the "current" // initializer. @@ -4019,8 +4007,9 @@ InitializationSequence::Perform(Sema &S, // the definition for completely trivial constructors. CXXRecordDecl *ClassDecl = Constructor->getParent(); assert(ClassDecl && "No parent class for constructor."); - if (Constructor->isImplicit() && Constructor->isDefaultConstructor() && - ClassDecl->hasTrivialConstructor() && !Constructor->isUsed(false)) + if (Constructor->isDefaulted() && Constructor->isDefaultConstructor() && + ClassDecl->hasTrivialDefaultConstructor() && + !Constructor->isUsed(false)) S.DefineImplicitDefaultConstructor(Loc, Constructor); } @@ -4060,8 +4049,7 @@ InitializationSequence::Perform(Sema &S, ConstructKind = Entity.getBaseSpecifier()->isVirtual() ? CXXConstructExpr::CK_VirtualBase : CXXConstructExpr::CK_NonVirtualBase; - } - if (Entity.getKind() == InitializedEntity::EK_Delegating) { + } else if (Entity.getKind() == InitializedEntity::EK_Delegating) { ConstructKind = CXXConstructExpr::CK_Delegating; } @@ -4216,7 +4204,7 @@ bool InitializationSequence::Diagnose(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr **Args, unsigned NumArgs) { - if (SequenceKind != FailedSequence) + if (!Failed()) return false; QualType DestType = Entity.getType(); @@ -4334,6 +4322,9 @@ bool InitializationSequence::Diagnose(Sema &S, << Args[0]->isLValue() << Args[0]->getType() << Args[0]->getSourceRange(); + if (DestType.getNonReferenceType()->isObjCObjectPointerType() && + Args[0]->getType()->isObjCObjectPointerType()) + S.EmitRelatedResultTypeNote(Args[0]); break; case FK_ConversionFailed: { @@ -4344,6 +4335,9 @@ bool InitializationSequence::Diagnose(Sema &S, << Args[0]->isLValue() << FromType << Args[0]->getSourceRange(); + if (DestType.getNonReferenceType()->isObjCObjectPointerType() && + Args[0]->getType()->isObjCObjectPointerType()) + S.EmitRelatedResultTypeNote(Args[0]); break; } @@ -4587,48 +4581,16 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { } case DependentSequence: - OS << "Dependent sequence: "; + OS << "Dependent sequence\n"; return; - case UserDefinedConversion: - OS << "User-defined conversion sequence: "; - break; - - case ConstructorInitialization: - OS << "Constructor initialization sequence: "; + case NormalSequence: + OS << "Normal sequence: "; break; case ReferenceBinding: OS << "Reference binding: "; break; - - case ListInitialization: - OS << "List initialization: "; - break; - - case ZeroInitialization: - OS << "Zero initialization\n"; - return; - - case NoInitialization: - OS << "No initialization\n"; - return; - - case StandardConversion: - OS << "Standard conversion: "; - break; - - case CAssignment: - OS << "C assignment: "; - break; - - case StringInit: - OS << "String initialization: "; - break; - - case ArrayInit: - OS << "Array initialization: "; - break; } for (step_iterator S = step_begin(), SEnd = step_end(); S != SEnd; ++S) { @@ -4723,6 +4685,21 @@ void InitializationSequence::dump() const { //===----------------------------------------------------------------------===// // Initialization helper functions //===----------------------------------------------------------------------===// +bool +Sema::CanPerformCopyInitialization(const InitializedEntity &Entity, + ExprResult Init) { + if (Init.isInvalid()) + return false; + + Expr *InitE = Init.get(); + assert(InitE && "No initialization expression"); + + InitializationKind Kind = InitializationKind::CreateCopy(SourceLocation(), + SourceLocation()); + InitializationSequence Seq(*this, Entity, Kind, &InitE, 1); + return !Seq.Failed(); +} + ExprResult Sema::PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 309c771..92ade1e 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -14,6 +14,7 @@ #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/Overload.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" @@ -534,7 +535,7 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) { return; // If the default constructor has not yet been declared, do so now. - if (!Class->hasDeclaredDefaultConstructor()) + if (Class->needsImplicitDefaultConstructor()) DeclareImplicitDefaultConstructor(Class); // If the copy constructor has not yet been declared, do so now. @@ -581,7 +582,7 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S, if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) if (Record->getDefinition() && CanDeclareSpecialMemberFunction(S.Context, Record)) { - if (!Record->hasDeclaredDefaultConstructor()) + if (Record->needsImplicitDefaultConstructor()) S.DeclareImplicitDefaultConstructor( const_cast<CXXRecordDecl *>(Record)); if (!Record->hasDeclaredCopyConstructor()) @@ -2136,11 +2137,200 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, } } +Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D, + CXXSpecialMember SM, + bool ConstArg, + bool VolatileArg, + bool RValueThis, + bool ConstThis, + bool VolatileThis) { + D = D->getDefinition(); + assert((D && !D->isBeingDefined()) && + "doing special member lookup into record that isn't fully complete"); + if (RValueThis || ConstThis || VolatileThis) + assert((SM == CXXCopyAssignment || SM == CXXMoveAssignment) && + "constructors and destructors always have unqualified lvalue this"); + if (ConstArg || VolatileArg) + assert((SM != CXXDefaultConstructor && SM != CXXDestructor) && + "parameter-less special members can't have qualified arguments"); + + llvm::FoldingSetNodeID ID; + ID.AddPointer(D); + ID.AddInteger(SM); + ID.AddInteger(ConstArg); + ID.AddInteger(VolatileArg); + ID.AddInteger(RValueThis); + ID.AddInteger(ConstThis); + ID.AddInteger(VolatileThis); + + void *InsertPoint; + SpecialMemberOverloadResult *Result = + SpecialMemberCache.FindNodeOrInsertPos(ID, InsertPoint); + + // This was already cached + if (Result) + return Result; + + Result = BumpAlloc.Allocate<SpecialMemberOverloadResult>(); + Result = new (Result) SpecialMemberOverloadResult(ID); + SpecialMemberCache.InsertNode(Result, InsertPoint); + + if (SM == CXXDestructor) { + if (!D->hasDeclaredDestructor()) + DeclareImplicitDestructor(D); + CXXDestructorDecl *DD = D->getDestructor(); + assert(DD && "record without a destructor"); + Result->setMethod(DD); + Result->setSuccess(DD->isDeleted()); + Result->setConstParamMatch(false); + return Result; + } + + // Prepare for overload resolution. Here we construct a synthetic argument + // if necessary and make sure that implicit functions are declared. + CanQualType CanTy = Context.getCanonicalType(Context.getTagDeclType(D)); + DeclarationName Name; + Expr *Arg = 0; + unsigned NumArgs; + + if (SM == CXXDefaultConstructor) { + Name = Context.DeclarationNames.getCXXConstructorName(CanTy); + NumArgs = 0; + if (D->needsImplicitDefaultConstructor()) + DeclareImplicitDefaultConstructor(D); + } else { + if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) { + Name = Context.DeclarationNames.getCXXConstructorName(CanTy); + if (!D->hasDeclaredCopyConstructor()) + DeclareImplicitCopyConstructor(D); + // TODO: Move constructors + } else { + Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); + if (!D->hasDeclaredCopyAssignment()) + DeclareImplicitCopyAssignment(D); + // TODO: Move assignment + } + + QualType ArgType = CanTy; + if (ConstArg) + ArgType.addConst(); + if (VolatileArg) + ArgType.addVolatile(); + + // This isn't /really/ specified by the standard, but it's implied + // we should be working from an RValue in the case of move to ensure + // that we prefer to bind to rvalue references, and an LValue in the + // case of copy to ensure we don't bind to rvalue references. + // Possibly an XValue is actually correct in the case of move, but + // there is no semantic difference for class types in this restricted + // case. + ExprValueKind VK; + if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) + VK = VK_LValue; + else + VK = VK_RValue; + + NumArgs = 1; + Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType, VK); + } + + // Create the object argument + QualType ThisTy = CanTy; + if (ConstThis) + ThisTy.addConst(); + if (VolatileThis) + ThisTy.addVolatile(); + Expr::Classification ObjectClassification = + (new (Context) OpaqueValueExpr(SourceLocation(), ThisTy, + RValueThis ? VK_RValue : VK_LValue))-> + Classify(Context); + + // Now we perform lookup on the name we computed earlier and do overload + // resolution. Lookup is only performed directly into the class since there + // will always be a (possibly implicit) declaration to shadow any others. + OverloadCandidateSet OCS((SourceLocation())); + DeclContext::lookup_iterator I, E; + Result->setConstParamMatch(false); + + llvm::tie(I, E) = D->lookup(Name); + assert((I != E) && + "lookup for a constructor or assignment operator was empty"); + for ( ; I != E; ++I) { + if ((*I)->isInvalidDecl()) + continue; + + if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I)) { + AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public), &Arg, NumArgs, + OCS, true); + + // Here we're looking for a const parameter to speed up creation of + // implicit copy methods. + if ((SM == CXXCopyAssignment && M->isCopyAssignmentOperator()) || + (SM == CXXCopyConstructor && + cast<CXXConstructorDecl>(M)->isCopyConstructor())) { + QualType ArgType = M->getType()->getAs<FunctionProtoType>()->getArgType(0); + if (ArgType->getPointeeType().isConstQualified()) + Result->setConstParamMatch(true); + } + } else { + FunctionTemplateDecl *Tmpl = cast<FunctionTemplateDecl>(*I); + AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public), + 0, &Arg, NumArgs, OCS, true); + } + } + + OverloadCandidateSet::iterator Best; + switch (OCS.BestViableFunction(*this, SourceLocation(), Best)) { + case OR_Success: + Result->setMethod(cast<CXXMethodDecl>(Best->Function)); + Result->setSuccess(true); + break; + + case OR_Deleted: + Result->setMethod(cast<CXXMethodDecl>(Best->Function)); + Result->setSuccess(false); + break; + + case OR_Ambiguous: + case OR_No_Viable_Function: + Result->setMethod(0); + Result->setSuccess(false); + break; + } + + return Result; +} + +/// \brief Look up the default constructor for the given class. +CXXConstructorDecl *Sema::LookupDefaultConstructor(CXXRecordDecl *Class) { + SpecialMemberOverloadResult *Result = + LookupSpecialMember(Class, CXXDefaultConstructor, false, false, false, + false, false); + + return cast_or_null<CXXConstructorDecl>(Result->getMethod()); +} + +/// \brief Look up the copy constructor for the given class. +CXXConstructorDecl *Sema::LookupCopyConstructor(CXXRecordDecl *Class, + unsigned Quals, + bool *ConstParamMatch) { + assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) && + "non-const, non-volatile qualifiers for copy ctor arg"); + SpecialMemberOverloadResult *Result = + LookupSpecialMember(Class, CXXCopyConstructor, Quals & Qualifiers::Const, + Quals & Qualifiers::Volatile, false, false, false); + + if (ConstParamMatch) + *ConstParamMatch = Result->hasConstParamMatch(); + + return cast_or_null<CXXConstructorDecl>(Result->getMethod()); +} + /// \brief Look up the constructors for the given class. DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { - // If the copy constructor has not yet been declared, do so now. + // If the implicit constructors have not yet been declared, do so now. if (CanDeclareSpecialMemberFunction(Context, Class)) { - if (!Class->hasDeclaredDefaultConstructor()) + if (Class->needsImplicitDefaultConstructor()) DeclareImplicitDefaultConstructor(Class); if (!Class->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(Class); @@ -2158,12 +2348,9 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { /// /// \returns The destructor for this class. CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) { - // If the destructor has not yet been declared, do so now. - if (CanDeclareSpecialMemberFunction(Context, Class) && - !Class->hasDeclaredDestructor()) - DeclareImplicitDestructor(Class); - - return Class->getDestructor(); + return cast<CXXDestructorDecl>(LookupSpecialMember(Class, CXXDestructor, + false, false, false, + false, false)->getMethod()); } void ADLResult::insert(NamedDecl *New) { @@ -2410,8 +2597,8 @@ VisibleDeclsRecord::ShadowMapEntry::end() { if (DeclOrVector.isNull()) return 0; - if (DeclOrVector.dyn_cast<NamedDecl *>()) - return &reinterpret_cast<NamedDecl*&>(DeclOrVector) + 1; + if (DeclOrVector.is<NamedDecl *>()) + return DeclOrVector.getAddrOf<NamedDecl *>() + 1; return DeclOrVector.get<DeclVector *>()->end(); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 3f3ed0e..4bba6f8 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1628,6 +1628,15 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, return true; } + // MSVC allows implicit function to void* type conversion. + if (getLangOptions().Microsoft && FromPointeeType->isFunctionType() && + ToPointeeType->isVoidType()) { + ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, + ToPointeeType, + ToType, Context); + return true; + } + // When we're overloading in C, we allow a special kind of pointer // conversion for compatible-but-not-identical pointee types. if (!getLangOptions().CPlusPlus && @@ -2197,6 +2206,13 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType, Qualifiers FromQuals = FromType.getQualifiers(); Qualifiers ToQuals = ToType.getQualifiers(); + // Allow addition/removal of GC attributes but not changing GC attributes. + if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() && + (!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) { + FromQuals.removeObjCGCAttr(); + ToQuals.removeObjCGCAttr(); + } + // -- for every j > 0, if const is in cv 1,j then const is in cv // 2,j, and similarly for volatile. if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals)) @@ -2507,12 +2523,10 @@ compareStandardConversionSubsets(ASTContext &Context, // the identity conversion sequence is considered to be a subsequence of // any non-identity conversion sequence - if (SCS1.ReferenceBinding == SCS2.ReferenceBinding) { - if (SCS1.isIdentityConversion() && !SCS2.isIdentityConversion()) - return ImplicitConversionSequence::Better; - else if (!SCS1.isIdentityConversion() && SCS2.isIdentityConversion()) - return ImplicitConversionSequence::Worse; - } + if (SCS1.isIdentityConversion() && !SCS2.isIdentityConversion()) + return ImplicitConversionSequence::Better; + else if (!SCS1.isIdentityConversion() && SCS2.isIdentityConversion()) + return ImplicitConversionSequence::Worse; if (SCS1.Second != SCS2.Second) { if (SCS1.Second == ICK_Identity) @@ -4689,6 +4703,10 @@ class BuiltinCandidateTypeSet { /// were present in the candidate set. bool HasArithmeticOrEnumeralTypes; + /// \brief A flag indicating whether the nullptr type was present in the + /// candidate set. + bool HasNullPtrType; + /// Sema - The semantic analysis instance where we are building the /// candidate type set. Sema &SemaRef; @@ -4707,6 +4725,7 @@ public: BuiltinCandidateTypeSet(Sema &SemaRef) : HasNonRecordTypes(false), HasArithmeticOrEnumeralTypes(false), + HasNullPtrType(false), SemaRef(SemaRef), Context(SemaRef.Context) { } @@ -4739,6 +4758,7 @@ public: bool hasNonRecordTypes() { return HasNonRecordTypes; } bool hasArithmeticOrEnumeralTypes() { return HasArithmeticOrEnumeralTypes; } + bool hasNullPtrType() const { return HasNullPtrType; } }; /// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to @@ -4899,6 +4919,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, // extension. HasArithmeticOrEnumeralTypes = true; VectorTypes.insert(Ty); + } else if (Ty->isNullPtrType()) { + HasNullPtrType = true; } else if (AllowUserConversions && TyRec) { // No conversion functions in incomplete types. if (SemaRef.RequireCompleteType(Loc, Ty, 0)) @@ -5358,8 +5380,8 @@ public: // C++ [over.built]p15: // - // For every pointer or enumeration type T, there exist - // candidate operator functions of the form + // For every T, where T is an enumeration type, a pointer type, or + // std::nullptr_t, there exist candidate operator functions of the form // // bool operator<(T, T); // bool operator>(T, T); @@ -5444,6 +5466,17 @@ public: S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, CandidateSet); } + + if (CandidateTypes[ArgIdx].hasNullPtrType()) { + CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy); + if (AddedTypes.insert(NullPtrTy) && + !UserDefinedBinaryOperators.count(std::make_pair(NullPtrTy, + NullPtrTy))) { + QualType ParamTypes[2] = { NullPtrTy, NullPtrTy }; + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, + CandidateSet); + } + } } } @@ -6401,7 +6434,9 @@ enum OverloadCandidateKind { oc_constructor_template, oc_implicit_default_constructor, oc_implicit_copy_constructor, + oc_implicit_move_constructor, oc_implicit_copy_assignment, + oc_implicit_move_assignment, oc_implicit_inherited_constructor }; @@ -6423,8 +6458,15 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S, if (Ctor->getInheritedConstructor()) return oc_implicit_inherited_constructor; - return Ctor->isCopyConstructor() ? oc_implicit_copy_constructor - : oc_implicit_default_constructor; + if (Ctor->isDefaultConstructor()) + return oc_implicit_default_constructor; + + if (Ctor->isMoveConstructor()) + return oc_implicit_move_constructor; + + assert(Ctor->isCopyConstructor() && + "unexpected sort of implicit constructor"); + return oc_implicit_copy_constructor; } if (CXXMethodDecl *Meth = dyn_cast<CXXMethodDecl>(Fn)) { @@ -6433,6 +6475,9 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S, if (!Meth->isImplicit()) return isTemplate ? oc_method_template : oc_method; + if (Meth->isMoveAssignmentOperator()) + return oc_implicit_move_assignment; + assert(Meth->isCopyAssignmentOperator() && "implicit method is not copy assignment operator?"); return oc_implicit_copy_assignment; @@ -6676,6 +6721,15 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, unsigned MinParams = Fn->getMinRequiredArguments(); + // With invalid overloaded operators, it's possible that we think we + // have an arity mismatch when it fact it looks like we have the + // right number of arguments, because only overloaded operators have + // the weird behavior of overloading member and non-member functions. + // Just don't report anything. + if (Fn->isInvalidDecl() && + Fn->getDeclName().getNameKind() == DeclarationName::CXXOperatorName) + return; + // at least / at most / exactly unsigned mode, modeCount; if (NumFormalArgs < MinParams) { @@ -7772,6 +7826,111 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, ULE->isStdAssociatedNamespace()); } +/// Attempt to recover from an ill-formed use of a non-dependent name in a +/// template, where the non-dependent name was declared after the template +/// was defined. This is common in code written for a compilers which do not +/// correctly implement two-stage name lookup. +/// +/// Returns true if a viable candidate was found and a diagnostic was issued. +static bool +DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc, + const CXXScopeSpec &SS, LookupResult &R, + TemplateArgumentListInfo *ExplicitTemplateArgs, + Expr **Args, unsigned NumArgs) { + if (SemaRef.ActiveTemplateInstantiations.empty() || !SS.isEmpty()) + return false; + + for (DeclContext *DC = SemaRef.CurContext; DC; DC = DC->getParent()) { + SemaRef.LookupQualifiedName(R, DC); + + if (!R.empty()) { + R.suppressDiagnostics(); + + if (isa<CXXRecordDecl>(DC)) { + // Don't diagnose names we find in classes; we get much better + // diagnostics for these from DiagnoseEmptyLookup. + R.clear(); + return false; + } + + OverloadCandidateSet Candidates(FnLoc); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) + AddOverloadedCallCandidate(SemaRef, I.getPair(), + ExplicitTemplateArgs, Args, NumArgs, + Candidates, false); + + OverloadCandidateSet::iterator Best; + if (Candidates.BestViableFunction(SemaRef, FnLoc, Best) != OR_Success) + // No viable functions. Don't bother the user with notes for functions + // which don't work and shouldn't be found anyway. + return false; + + // Find the namespaces where ADL would have looked, and suggest + // declaring the function there instead. + Sema::AssociatedNamespaceSet AssociatedNamespaces; + Sema::AssociatedClassSet AssociatedClasses; + SemaRef.FindAssociatedClassesAndNamespaces(Args, NumArgs, + AssociatedNamespaces, + AssociatedClasses); + // Never suggest declaring a function within namespace 'std'. + Sema::AssociatedNamespaceSet SuggestedNamespaces; + if (DeclContext *Std = SemaRef.getStdNamespace()) { + for (Sema::AssociatedNamespaceSet::iterator + it = AssociatedNamespaces.begin(), + end = AssociatedNamespaces.end(); it != end; ++it) { + if (!Std->Encloses(*it)) + SuggestedNamespaces.insert(*it); + } + } else { + // Lacking the 'std::' namespace, use all of the associated namespaces. + SuggestedNamespaces = AssociatedNamespaces; + } + + SemaRef.Diag(R.getNameLoc(), diag::err_not_found_by_two_phase_lookup) + << R.getLookupName(); + if (SuggestedNamespaces.empty()) { + SemaRef.Diag(Best->Function->getLocation(), + diag::note_not_found_by_two_phase_lookup) + << R.getLookupName() << 0; + } else if (SuggestedNamespaces.size() == 1) { + SemaRef.Diag(Best->Function->getLocation(), + diag::note_not_found_by_two_phase_lookup) + << R.getLookupName() << 1 << *SuggestedNamespaces.begin(); + } else { + // FIXME: It would be useful to list the associated namespaces here, + // but the diagnostics infrastructure doesn't provide a way to produce + // a localized representation of a list of items. + SemaRef.Diag(Best->Function->getLocation(), + diag::note_not_found_by_two_phase_lookup) + << R.getLookupName() << 2; + } + + // Try to recover by calling this function. + return true; + } + + R.clear(); + } + + return false; +} + +/// Attempt to recover from ill-formed use of a non-dependent operator in a +/// template, where the non-dependent operator was declared after the template +/// was defined. +/// +/// Returns true if a viable candidate was found and a diagnostic was issued. +static bool +DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op, + SourceLocation OpLoc, + Expr **Args, unsigned NumArgs) { + DeclarationName OpName = + SemaRef.Context.DeclarationNames.getCXXOperatorName(Op); + LookupResult R(SemaRef, OpName, OpLoc, Sema::LookupOperatorName); + return DiagnoseTwoPhaseLookup(SemaRef, OpLoc, CXXScopeSpec(), R, + /*ExplicitTemplateArgs=*/0, Args, NumArgs); +} + /// Attempts to recover from a call where no functions were found. /// /// Returns true if new candidates were found. @@ -7780,13 +7939,14 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + bool EmptyLookup) { CXXScopeSpec SS; SS.Adopt(ULE->getQualifierLoc()); TemplateArgumentListInfo TABuffer; - const TemplateArgumentListInfo *ExplicitTemplateArgs = 0; + TemplateArgumentListInfo *ExplicitTemplateArgs = 0; if (ULE->hasExplicitTemplateArgs()) { ULE->copyTemplateArgumentsInto(TABuffer); ExplicitTemplateArgs = &TABuffer; @@ -7794,7 +7954,10 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(), Sema::LookupOrdinaryName); - if (SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression)) + if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R, + ExplicitTemplateArgs, Args, NumArgs) && + (!EmptyLookup || + SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression))) return ExprError(); assert(!R.empty() && "lookup results empty despite recovery"); @@ -7814,7 +7977,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, return ExprError(); // This shouldn't cause an infinite loop because we're giving it - // an expression with non-empty lookup results, which should never + // an expression with viable lookup results, which should never // end up here. return SemaRef.ActOnCallExpr(/*Scope*/ 0, NewFn.take(), LParenLoc, MultiExprArg(Args, NumArgs), RParenLoc); @@ -7860,11 +8023,11 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, AddOverloadedCallCandidates(ULE, Args, NumArgs, CandidateSet); // If we found nothing, try to recover. - // AddRecoveryCallCandidates diagnoses the error itself, so we just - // bailout out if it fails. + // BuildRecoveryCallExpr diagnoses the error itself, so we just bail + // out if it fails. if (CandidateSet.empty()) return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs, - RParenLoc); + RParenLoc, /*EmptyLookup=*/true); OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) { @@ -7879,12 +8042,21 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, ExecConfig); } - case OR_No_Viable_Function: + case OR_No_Viable_Function: { + // Try to recover by looking for viable functions which the user might + // have meant to call. + ExprResult Recovery = BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, + Args, NumArgs, RParenLoc, + /*EmptyLookup=*/false); + if (!Recovery.isInvalid()) + return Recovery; + Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_no_viable_function_in_call) << ULE->getName() << Fn->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); break; + } case OR_Ambiguous: Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_ambiguous_call) @@ -8073,6 +8245,13 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, } case OR_No_Viable_Function: + // This is an erroneous use of an operator which can be overloaded by + // a non-member function. Check for non-member operators which were + // defined too late to be candidates. + if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, Args, NumArgs)) + // FIXME: Recover by calling the found function. + return ExprError(); + // No viable function; fall through to handling this as a // built-in operator, which will produce an error message for us. break; @@ -8354,6 +8533,13 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, << BinaryOperator::getOpcodeStr(Opc) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); } else { + // This is an erroneous use of an operator which can be overloaded by + // a non-member function. Check for non-member operators which were + // defined too late to be candidates. + if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, Args, 2)) + // FIXME: Recover by calling the found function. + return ExprError(); + // No viable function; try to create a built-in operation, which will // produce an error. Then, show the non-viable candidates. Result = CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); @@ -8772,6 +8958,19 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, if (CheckFunctionCall(Method, TheCall)) return ExprError(); + if ((isa<CXXConstructorDecl>(CurContext) || + isa<CXXDestructorDecl>(CurContext)) && + TheCall->getMethodDecl()->isPure()) { + const CXXMethodDecl *MD = TheCall->getMethodDecl(); + + if (isa<CXXThisExpr>(MemExpr->getBase()->IgnoreParenCasts())) + Diag(MemExpr->getLocStart(), + diag::warn_call_to_pure_virtual_member_function_from_ctor_dtor) + << MD->getDeclName() << isa<CXXDestructorDecl>(CurContext) + << MD->getParent()->getDeclName(); + + Diag(MD->getLocStart(), diag::note_previous_decl) << MD->getDeclName(); + } return MaybeBindToTemporary(TheCall); } diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 65cea7a..d7c0a54 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -501,7 +501,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, = CondExpr->isTypeDependent() || CondExpr->isValueDependent(); unsigned CondWidth = HasDependentValue ? 0 : Context.getIntWidth(CondTypeBeforePromotion); - bool CondIsSigned = CondTypeBeforePromotion->isSignedIntegerType(); + bool CondIsSigned + = CondTypeBeforePromotion->isSignedIntegerOrEnumerationType(); // Accumulate all of the case values in a vector so that we can sort them // and detect duplicates. This vector contains the APInt for the case after @@ -723,7 +724,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // If switch has default case, then ignore it. if (!CaseListIsErroneous && !HasConstantCond && ET) { const EnumDecl *ED = ET->getDecl(); - typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy; + typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> + EnumValsTy; EnumValsTy EnumVals; // Gather all enum values, set their type and sort them, @@ -1252,7 +1254,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, ExprResult BoundExpr; if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(UnqAT)) BoundExpr = Owned(IntegerLiteral::Create(Context, CAT->getSize(), - Context.IntTy, RangeLoc)); + Context.getPointerDiffType(), + RangeLoc)); else if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(UnqAT)) BoundExpr = VAT->getSizeExpr(); @@ -1455,7 +1458,10 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { /// \param E The expression being returned from the function or block, or /// being thrown. /// -/// \param AllowFunctionParameter +/// \param AllowFunctionParameter Whether we allow function parameters to +/// be considered NRVO candidates. C++ prohibits this for NRVO itself, but +/// we re-use this logic to determine whether we should try to move as part of +/// a return or throw (which does allow function parameters). /// /// \returns The NRVO candidate variable, if the return statement may use the /// NRVO, or NULL if there is no such candidate. @@ -1525,12 +1531,11 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, // parameter of the selected constructor is not an rvalue reference // to the object's type (possibly cv-qualified), overload resolution // is performed again, considering the object as an lvalue. - if (Seq.getKind() != InitializationSequence::FailedSequence) { + if (Seq) { for (InitializationSequence::step_iterator Step = Seq.step_begin(), StepEnd = Seq.step_end(); Step != StepEnd; ++Step) { - if (Step->Kind - != InitializationSequence::SK_ConstructorInitialization) + if (Step->Kind != InitializationSequence::SK_ConstructorInitialization) continue; CXXConstructorDecl *Constructor @@ -1583,14 +1588,18 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (Result.isInvalid()) return StmtError(); RetValExp = Result.take(); - CurBlock->ReturnType = RetValExp->getType(); - if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) { - // We have to remove a 'const' added to copied-in variable which was - // part of the implementation spec. and not the actual qualifier for - // the variable. - if (CDRE->isConstQualAdded()) - CurBlock->ReturnType.removeLocalConst(); // FIXME: local??? - } + + if (!RetValExp->isTypeDependent()) { + CurBlock->ReturnType = RetValExp->getType(); + if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) { + // We have to remove a 'const' added to copied-in variable which was + // part of the implementation spec. and not the actual qualifier for + // the variable. + if (CDRE->isConstQualAdded()) + CurBlock->ReturnType.removeLocalConst(); // FIXME: local??? + } + } else + CurBlock->ReturnType = Context.DependentTy; } else CurBlock->ReturnType = Context.VoidTy; } @@ -1607,13 +1616,17 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // compatibility to worry about here. ReturnStmt *Result = 0; if (CurBlock->ReturnType->isVoidType()) { - if (RetValExp) { + if (RetValExp && !RetValExp->isTypeDependent() && + (!getLangOptions().CPlusPlus || !RetValExp->getType()->isVoidType())) { Diag(ReturnLoc, diag::err_return_block_has_expr); RetValExp = 0; } Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0); } else if (!RetValExp) { - return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr)); + if (!CurBlock->ReturnType->isDependentType()) + return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr)); + + Result = new (Context) ReturnStmt(ReturnLoc, 0, 0); } else { const VarDecl *NRVOCandidate = 0; @@ -1652,7 +1665,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // If we need to check for the named return value optimization, save the // return statement in our scope for later processing. - if (getLangOptions().CPlusPlus && FnRetType->isRecordType() && + if (getLangOptions().CPlusPlus && FnRetType->isRecordType() && !CurContext->isDependentContext()) FunctionScopes.back()->Returns.push_back(Result); @@ -1661,44 +1674,62 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { StmtResult Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { + // Check for unexpanded parameter packs. + if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp)) + return StmtError(); + if (getCurBlock()) return ActOnBlockReturnStmt(ReturnLoc, RetValExp); QualType FnRetType; + QualType DeclaredRetType; if (const FunctionDecl *FD = getCurFunctionDecl()) { FnRetType = FD->getResultType(); + DeclaredRetType = FnRetType; if (FD->hasAttr<NoReturnAttr>() || FD->getType()->getAs<FunctionType>()->getNoReturnAttr()) Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr) << getCurFunctionOrMethodDecl()->getDeclName(); - } else if (ObjCMethodDecl *MD = getCurMethodDecl()) - FnRetType = MD->getResultType(); - else // If we don't have a function/method context, bail. + } else if (ObjCMethodDecl *MD = getCurMethodDecl()) { + DeclaredRetType = MD->getResultType(); + if (MD->hasRelatedResultType() && MD->getClassInterface()) { + // In the implementation of a method with a related return type, the + // type used to type-check the validity of return statements within the + // method body is a pointer to the type of the class being implemented. + FnRetType = Context.getObjCInterfaceType(MD->getClassInterface()); + FnRetType = Context.getObjCObjectPointerType(FnRetType); + } else { + FnRetType = DeclaredRetType; + } + } else // If we don't have a function/method context, bail. return StmtError(); ReturnStmt *Result = 0; if (FnRetType->isVoidType()) { - if (RetValExp && !RetValExp->isTypeDependent()) { - // C99 6.8.6.4p1 (ext_ since GCC warns) - unsigned D = diag::ext_return_has_expr; - if (RetValExp->getType()->isVoidType()) - D = diag::ext_return_has_void_expr; - else { - ExprResult Result = Owned(RetValExp); - Result = IgnoredValueConversions(Result.take()); - if (Result.isInvalid()) - return StmtError(); - RetValExp = Result.take(); - RetValExp = ImpCastExprToType(RetValExp, Context.VoidTy, CK_ToVoid).take(); - } + if (RetValExp) { + if (!RetValExp->isTypeDependent()) { + // C99 6.8.6.4p1 (ext_ since GCC warns) + unsigned D = diag::ext_return_has_expr; + if (RetValExp->getType()->isVoidType()) + D = diag::ext_return_has_void_expr; + else { + ExprResult Result = Owned(RetValExp); + Result = IgnoredValueConversions(Result.take()); + if (Result.isInvalid()) + return StmtError(); + RetValExp = Result.take(); + RetValExp = ImpCastExprToType(RetValExp, + Context.VoidTy, CK_ToVoid).take(); + } - // return (some void expression); is legal in C++. - if (D != diag::ext_return_has_void_expr || - !getLangOptions().CPlusPlus) { - NamedDecl *CurDecl = getCurFunctionOrMethodDecl(); - Diag(ReturnLoc, D) - << CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl) - << RetValExp->getSourceRange(); + // return (some void expression); is legal in C++. + if (D != diag::ext_return_has_void_expr || + !getLangOptions().CPlusPlus) { + NamedDecl *CurDecl = getCurFunctionOrMethodDecl(); + Diag(ReturnLoc, D) + << CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl) + << RetValExp->getSourceRange(); + } } CheckImplicitConversions(RetValExp, ReturnLoc); @@ -1730,7 +1761,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, FnRetType, - NRVOCandidate != 0); + NRVOCandidate != 0); ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate, FnRetType, RetValExp); if (Res.isInvalid()) { @@ -1744,6 +1775,17 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { } if (RetValExp) { + // If we type-checked an Objective-C method's return type based + // on a related return type, we may need to adjust the return + // type again. Do so now. + if (DeclaredRetType != FnRetType) { + ExprResult result = PerformImplicitConversion(RetValExp, + DeclaredRetType, + AA_Returning); + if (result.isInvalid()) return StmtError(); + RetValExp = result.take(); + } + CheckImplicitConversions(RetValExp, ReturnLoc); RetValExp = MaybeCreateExprWithCleanups(RetValExp); } @@ -2015,7 +2057,9 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, if (InputDomain == AD_Int && OutputDomain == AD_Int && !isOperandMentioned(InputOpNo, Pieces) && InputExpr->isEvaluatable(Context)) { - InputExpr = ImpCastExprToType(InputExpr, OutTy, CK_IntegralCast).take(); + CastKind castKind = + (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast); + InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).take(); Exprs[InputOpNo] = InputExpr; NS->setInputExpr(i, InputExpr); continue; @@ -2251,7 +2295,9 @@ Sema::ActOnSEHExceptBlock(SourceLocation Loc, assert(FilterExpr && Block); if(!FilterExpr->getType()->isIntegerType()) { - return StmtError(Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral) << FilterExpr->getType()); + return StmtError(Diag(FilterExpr->getExprLoc(), + diag::err_filter_expression_integral) + << FilterExpr->getType()); } return Owned(SEHExceptStmt::Create(Context,Loc,FilterExpr,Block)); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index ef09124..5d4caac 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -92,11 +92,9 @@ void Sema::FilterAcceptableTemplateNames(LookupResult &R) { // ambiguity in certain cases (for example, if it is found in more than // one base class). If all of the injected-class-names that are found // refer to specializations of the same class template, and if the name - // is followed by a template-argument-list, the reference refers to the - // class template itself and not a specialization thereof, and is not + // is used as a template-name, the reference refers to the class + // template itself and not a specialization thereof, and is not // ambiguous. - // - // FIXME: Will we eventually have to do the same for alias templates? if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl)) if (!ClassTemplates.insert(ClassTmpl)) { filter.erase(); @@ -199,7 +197,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // We'll do this lookup again later. R.suppressDiagnostics(); } else { - assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD)); + assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) || + isa<TypeAliasTemplateDecl>(TD)); TemplateKind = TNK_Type_template; } } @@ -603,8 +602,10 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { T->isPointerType() || // -- reference to object or reference to function, T->isReferenceType() || - // -- pointer to member. + // -- pointer to member, T->isMemberPointerType() || + // -- std::nullptr_t. + T->isNullPtrType() || // If T is a dependent type, we can't do the check now, so we // assume that it is well-formed. T->isDependentType()) @@ -919,7 +920,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // the class-key shall agree in kind with the original class // template declaration (7.1.5.3). RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl(); - if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, KWLoc, *Name)) { + if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, + TUK == TUK_Definition, KWLoc, *Name)) { Diag(KWLoc, diag::err_use_with_wrong_tag) << Name << FixItHint::CreateReplacement(KWLoc, PrevRecordDecl->getKindName()); @@ -1062,6 +1064,7 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S, SourceRange DefArgRange) { switch (TPC) { case Sema::TPC_ClassTemplate: + case Sema::TPC_TypeAliasTemplate: return false; case Sema::TPC_FunctionTemplate: @@ -1187,9 +1190,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, bool MissingDefaultArg = false; // C++0x [temp.param]p11: - // If a template parameter of a primary class template is a template - // parameter pack, it shall be the last template parameter. - if (SawParameterPack && TPC == TPC_ClassTemplate) { + // If a template parameter of a primary class template or alias template + // is a template parameter pack, it shall be the last template parameter. + if (SawParameterPack && + (TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) { Diag(ParameterPackLoc, diag::err_template_param_pack_must_be_last_template_parameter); Invalid = true; @@ -1429,19 +1433,41 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> { } return super::VisitDeclRefExpr(E); } + + bool TraverseInjectedClassNameType(const InjectedClassNameType *T) { + return TraverseType(T->getInjectedSpecializationType()); + } }; } -/// Determines whether a template-id depends on the given parameter +/// Determines whether a given type depends on the given parameter /// list. static bool -DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId, - TemplateParameterList *Params) { +DependsOnTemplateParameters(QualType T, TemplateParameterList *Params) { DependencyChecker Checker(Params); - Checker.TraverseType(QualType(TemplateId, 0)); + Checker.TraverseType(T); return Checker.Match; } +// Find the source range corresponding to the named type in the given +// nested-name-specifier, if any. +static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context, + QualType T, + const CXXScopeSpec &SS) { + NestedNameSpecifierLoc NNSLoc(SS.getScopeRep(), SS.location_data()); + while (NestedNameSpecifier *NNS = NNSLoc.getNestedNameSpecifier()) { + if (const Type *CurType = NNS->getAsType()) { + if (Context.hasSameUnqualifiedType(T, QualType(CurType, 0))) + return NNSLoc.getTypeLoc().getSourceRange(); + } else + break; + + NNSLoc = NNSLoc.getPrefix(); + } + + return SourceRange(); +} + /// \brief Match the given template parameter lists to the given scope /// specifier, returning the template parameter list that applies to the /// name. @@ -1449,6 +1475,8 @@ DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId, /// \param DeclStartLoc the start of the declaration that has a scope /// specifier or a template parameter list. /// +/// \param DeclLoc The location of the declaration itself. +/// /// \param SS the scope specifier that will be matched to the given template /// parameter lists. This scope specifier precedes a qualified name that is /// being declared. @@ -1473,6 +1501,7 @@ DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId, /// itself a template). TemplateParameterList * Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, + SourceLocation DeclLoc, const CXXScopeSpec &SS, TemplateParameterList **ParamLists, unsigned NumParamLists, @@ -1480,138 +1509,268 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, bool &IsExplicitSpecialization, bool &Invalid) { IsExplicitSpecialization = false; - - // Find the template-ids that occur within the nested-name-specifier. These - // template-ids will match up with the template parameter lists. - llvm::SmallVector<const TemplateSpecializationType *, 4> - TemplateIdsInSpecifier; - llvm::SmallVector<ClassTemplateSpecializationDecl *, 4> - ExplicitSpecializationsInSpecifier; - for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); - NNS; NNS = NNS->getPrefix()) { - const Type *T = NNS->getAsType(); - if (!T) break; - - // C++0x [temp.expl.spec]p17: - // A member or a member template may be nested within many - // enclosing class templates. In an explicit specialization for - // such a member, the member declaration shall be preceded by a - // template<> for each enclosing class template that is - // explicitly specialized. - // - // Following the existing practice of GNU and EDG, we allow a typedef of a - // template specialization type. - while (const TypedefType *TT = dyn_cast<TypedefType>(T)) - T = TT->getDecl()->getUnderlyingType().getTypePtr(); - - if (const TemplateSpecializationType *SpecType - = dyn_cast<TemplateSpecializationType>(T)) { - TemplateDecl *Template = SpecType->getTemplateName().getAsTemplateDecl(); - if (!Template) - continue; // FIXME: should this be an error? probably... - - if (const RecordType *Record = SpecType->getAs<RecordType>()) { - ClassTemplateSpecializationDecl *SpecDecl - = cast<ClassTemplateSpecializationDecl>(Record->getDecl()); - // If the nested name specifier refers to an explicit specialization, - // we don't need a template<> header. - if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization) { - ExplicitSpecializationsInSpecifier.push_back(SpecDecl); - continue; + Invalid = false; + + // The sequence of nested types to which we will match up the template + // parameter lists. We first build this list by starting with the type named + // by the nested-name-specifier and walking out until we run out of types. + llvm::SmallVector<QualType, 4> NestedTypes; + QualType T; + if (SS.getScopeRep()) { + if (CXXRecordDecl *Record + = dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(SS, true))) + T = Context.getTypeDeclType(Record); + else + T = QualType(SS.getScopeRep()->getAsType(), 0); + } + + // If we found an explicit specialization that prevents us from needing + // 'template<>' headers, this will be set to the location of that + // explicit specialization. + SourceLocation ExplicitSpecLoc; + + while (!T.isNull()) { + NestedTypes.push_back(T); + + // Retrieve the parent of a record type. + if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) { + // If this type is an explicit specialization, we're done. + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Record)) { + if (!isa<ClassTemplatePartialSpecializationDecl>(Spec) && + Spec->getSpecializationKind() == TSK_ExplicitSpecialization) { + ExplicitSpecLoc = Spec->getLocation(); + break; } + } else if (Record->getTemplateSpecializationKind() + == TSK_ExplicitSpecialization) { + ExplicitSpecLoc = Record->getLocation(); + break; + } + + if (TypeDecl *Parent = dyn_cast<TypeDecl>(Record->getParent())) + T = Context.getTypeDeclType(Parent); + else + T = QualType(); + continue; + } + + if (const TemplateSpecializationType *TST + = T->getAs<TemplateSpecializationType>()) { + if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) { + if (TypeDecl *Parent = dyn_cast<TypeDecl>(Template->getDeclContext())) + T = Context.getTypeDeclType(Parent); + else + T = QualType(); + continue; } - - TemplateIdsInSpecifier.push_back(SpecType); } - } - - // Reverse the list of template-ids in the scope specifier, so that we can - // more easily match up the template-ids and the template parameter lists. - std::reverse(TemplateIdsInSpecifier.begin(), TemplateIdsInSpecifier.end()); - - SourceLocation FirstTemplateLoc = DeclStartLoc; - if (NumParamLists) - FirstTemplateLoc = ParamLists[0]->getTemplateLoc(); - - // Match the template-ids found in the specifier to the template parameter - // lists. - unsigned ParamIdx = 0, TemplateIdx = 0; - for (unsigned NumTemplateIds = TemplateIdsInSpecifier.size(); - TemplateIdx != NumTemplateIds; ++TemplateIdx) { - const TemplateSpecializationType *TemplateId - = TemplateIdsInSpecifier[TemplateIdx]; - bool DependentTemplateId = TemplateId->isDependentType(); - - // In friend declarations we can have template-ids which don't - // depend on the corresponding template parameter lists. But - // assume that empty parameter lists are supposed to match this - // template-id. - if (IsFriend && ParamIdx < NumParamLists && ParamLists[ParamIdx]->size()) { - if (!DependentTemplateId || - !DependsOnTemplateParameters(TemplateId, ParamLists[ParamIdx])) - continue; + + // Look one step prior in a dependent template specialization type. + if (const DependentTemplateSpecializationType *DependentTST + = T->getAs<DependentTemplateSpecializationType>()) { + if (NestedNameSpecifier *NNS = DependentTST->getQualifier()) + T = QualType(NNS->getAsType(), 0); + else + T = QualType(); + continue; + } + + // Look one step prior in a dependent name type. + if (const DependentNameType *DependentName = T->getAs<DependentNameType>()){ + if (NestedNameSpecifier *NNS = DependentName->getQualifier()) + T = QualType(NNS->getAsType(), 0); + else + T = QualType(); + continue; + } + + // Retrieve the parent of an enumeration type. + if (const EnumType *EnumT = T->getAs<EnumType>()) { + // FIXME: Forward-declared enums require a TSK_ExplicitSpecialization + // check here. + EnumDecl *Enum = EnumT->getDecl(); + + // Get to the parent type. + if (TypeDecl *Parent = dyn_cast<TypeDecl>(Enum->getParent())) + T = Context.getTypeDeclType(Parent); + else + T = QualType(); + continue; } - if (ParamIdx >= NumParamLists) { - // We have a template-id without a corresponding template parameter - // list. + T = QualType(); + } + // Reverse the nested types list, since we want to traverse from the outermost + // to the innermost while checking template-parameter-lists. + std::reverse(NestedTypes.begin(), NestedTypes.end()); + + // C++0x [temp.expl.spec]p17: + // A member or a member template may be nested within many + // enclosing class templates. In an explicit specialization for + // such a member, the member declaration shall be preceded by a + // template<> for each enclosing class template that is + // explicitly specialized. + bool SawNonEmptyTemplateParameterList = false; + unsigned ParamIdx = 0; + for (unsigned TypeIdx = 0, NumTypes = NestedTypes.size(); TypeIdx != NumTypes; + ++TypeIdx) { + T = NestedTypes[TypeIdx]; + + // Whether we expect a 'template<>' header. + bool NeedEmptyTemplateHeader = false; - // ...which is fine if this is a friend declaration. - if (IsFriend) { - IsExplicitSpecialization = true; - break; + // Whether we expect a template header with parameters. + bool NeedNonemptyTemplateHeader = false; + + // For a dependent type, the set of template parameters that we + // expect to see. + TemplateParameterList *ExpectedTemplateParams = 0; + + // C++0x [temp.expl.spec]p15: + // A member or a member template may be nested within many enclosing + // class templates. In an explicit specialization for such a member, the + // member declaration shall be preceded by a template<> for each + // enclosing class template that is explicitly specialized. + if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) { + if (ClassTemplatePartialSpecializationDecl *Partial + = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) { + ExpectedTemplateParams = Partial->getTemplateParameters(); + NeedNonemptyTemplateHeader = true; + } else if (Record->isDependentType()) { + if (Record->getDescribedClassTemplate()) { + ExpectedTemplateParams = Record->getDescribedClassTemplate() + ->getTemplateParameters(); + NeedNonemptyTemplateHeader = true; + } + } else if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Record)) { + // C++0x [temp.expl.spec]p4: + // Members of an explicitly specialized class template are defined + // in the same manner as members of normal classes, and not using + // the template<> syntax. + if (Spec->getSpecializationKind() != TSK_ExplicitSpecialization) + NeedEmptyTemplateHeader = true; + else + continue; + } else if (Record->getTemplateSpecializationKind()) { + if (Record->getTemplateSpecializationKind() + != TSK_ExplicitSpecialization && + TypeIdx == NumTypes - 1) + IsExplicitSpecialization = true; + + continue; } - - if (DependentTemplateId) { - // FIXME: the location information here isn't great. - Diag(SS.getRange().getBegin(), - diag::err_template_spec_needs_template_parameters) - << QualType(TemplateId, 0) - << SS.getRange(); - Invalid = true; - } else { - Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_header) - << SS.getRange() - << FixItHint::CreateInsertion(FirstTemplateLoc, "template<> "); - IsExplicitSpecialization = true; + } else if (const TemplateSpecializationType *TST + = T->getAs<TemplateSpecializationType>()) { + if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) { + ExpectedTemplateParams = Template->getTemplateParameters(); + NeedNonemptyTemplateHeader = true; } - return 0; + } else if (T->getAs<DependentTemplateSpecializationType>()) { + // FIXME: We actually could/should check the template arguments here + // against the corresponding template parameter list. + NeedNonemptyTemplateHeader = false; + } + + // C++ [temp.expl.spec]p16: + // In an explicit specialization declaration for a member of a class + // template or a member template that ap- pears in namespace scope, the + // member template and some of its enclosing class templates may remain + // unspecialized, except that the declaration shall not explicitly + // specialize a class member template if its en- closing class templates + // are not explicitly specialized as well. + if (ParamIdx < NumParamLists) { + if (ParamLists[ParamIdx]->size() == 0) { + if (SawNonEmptyTemplateParameterList) { + Diag(DeclLoc, diag::err_specialize_member_of_template) + << ParamLists[ParamIdx]->getSourceRange(); + Invalid = true; + IsExplicitSpecialization = false; + return 0; + } + } else + SawNonEmptyTemplateParameterList = true; } - - // Check the template parameter list against its corresponding template-id. - if (DependentTemplateId) { - TemplateParameterList *ExpectedTemplateParams = 0; - - // Are there cases in (e.g.) friends where this won't match? - if (const InjectedClassNameType *Injected - = TemplateId->getAs<InjectedClassNameType>()) { - CXXRecordDecl *Record = Injected->getDecl(); - if (ClassTemplatePartialSpecializationDecl *Partial = - dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) - ExpectedTemplateParams = Partial->getTemplateParameters(); + + if (NeedEmptyTemplateHeader) { + // If we're on the last of the types, and we need a 'template<>' header + // here, then it's an explicit specialization. + if (TypeIdx == NumTypes - 1) + IsExplicitSpecialization = true; + + if (ParamIdx < NumParamLists) { + if (ParamLists[ParamIdx]->size() > 0) { + // The header has template parameters when it shouldn't. Complain. + Diag(ParamLists[ParamIdx]->getTemplateLoc(), + diag::err_template_param_list_matches_nontemplate) + << T + << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(), + ParamLists[ParamIdx]->getRAngleLoc()) + << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); + Invalid = true; + return 0; + } + + // Consume this template header. + ++ParamIdx; + continue; + } + + if (!IsFriend) { + // We don't have a template header, but we should. + SourceLocation ExpectedTemplateLoc; + if (NumParamLists > 0) + ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc(); else - ExpectedTemplateParams = Record->getDescribedClassTemplate() - ->getTemplateParameters(); - } + ExpectedTemplateLoc = DeclStartLoc; - if (ExpectedTemplateParams) - TemplateParameterListsAreEqual(ParamLists[ParamIdx], - ExpectedTemplateParams, - true, TPL_TemplateMatch); - - CheckTemplateParameterList(ParamLists[ParamIdx], 0, - TPC_ClassTemplateMember); - } else if (ParamLists[ParamIdx]->size() > 0) - Diag(ParamLists[ParamIdx]->getTemplateLoc(), - diag::err_template_param_list_matches_nontemplate) - << TemplateId - << ParamLists[ParamIdx]->getSourceRange(); - else - IsExplicitSpecialization = true; + Diag(DeclLoc, diag::err_template_spec_needs_header) + << getRangeOfTypeInNestedNameSpecifier(Context, T, SS) + << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> "); + } + + continue; + } + + if (NeedNonemptyTemplateHeader) { + // In friend declarations we can have template-ids which don't + // depend on the corresponding template parameter lists. But + // assume that empty parameter lists are supposed to match this + // template-id. + if (IsFriend && T->isDependentType()) { + if (ParamIdx < NumParamLists && + DependsOnTemplateParameters(T, ParamLists[ParamIdx])) + ExpectedTemplateParams = 0; + else + continue; + } - ++ParamIdx; + if (ParamIdx < NumParamLists) { + // Check the template parameter list, if we can. + if (ExpectedTemplateParams && + !TemplateParameterListsAreEqual(ParamLists[ParamIdx], + ExpectedTemplateParams, + true, TPL_TemplateMatch)) + Invalid = true; + + if (!Invalid && + CheckTemplateParameterList(ParamLists[ParamIdx], 0, + TPC_ClassTemplateMember)) + Invalid = true; + + ++ParamIdx; + continue; + } + + Diag(DeclLoc, diag::err_template_spec_needs_template_parameters) + << T + << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); + Invalid = true; + continue; + } } - + // If there were at least as many template-ids as there were template // parameter lists, then there are no template parameter lists remaining for // the declaration itself. @@ -1619,32 +1778,53 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, return 0; // If there were too many template parameter lists, complain about that now. - if (ParamIdx != NumParamLists - 1) { - while (ParamIdx < NumParamLists - 1) { - bool isExplicitSpecHeader = ParamLists[ParamIdx]->size() == 0; - Diag(ParamLists[ParamIdx]->getTemplateLoc(), - isExplicitSpecHeader? diag::warn_template_spec_extra_headers - : diag::err_template_spec_extra_headers) - << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(), - ParamLists[ParamIdx]->getRAngleLoc()); - - if (isExplicitSpecHeader && !ExplicitSpecializationsInSpecifier.empty()) { - Diag(ExplicitSpecializationsInSpecifier.back()->getLocation(), - diag::note_explicit_template_spec_does_not_need_header) - << ExplicitSpecializationsInSpecifier.back(); - ExplicitSpecializationsInSpecifier.pop_back(); - } - - // We have a template parameter list with no corresponding scope, which - // means that the resulting template declaration can't be instantiated - // properly (we'll end up with dependent nodes when we shouldn't). - if (!isExplicitSpecHeader) - Invalid = true; - - ++ParamIdx; + if (ParamIdx < NumParamLists - 1) { + bool HasAnyExplicitSpecHeader = false; + bool AllExplicitSpecHeaders = true; + for (unsigned I = ParamIdx; I != NumParamLists - 1; ++I) { + if (ParamLists[I]->size() == 0) + HasAnyExplicitSpecHeader = true; + else + AllExplicitSpecHeaders = false; } + + Diag(ParamLists[ParamIdx]->getTemplateLoc(), + AllExplicitSpecHeaders? diag::warn_template_spec_extra_headers + : diag::err_template_spec_extra_headers) + << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(), + ParamLists[NumParamLists - 2]->getRAngleLoc()); + + // If there was a specialization somewhere, such that 'template<>' is + // not required, and there were any 'template<>' headers, note where the + // specialization occurred. + if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader) + Diag(ExplicitSpecLoc, + diag::note_explicit_template_spec_does_not_need_header) + << NestedTypes.back(); + + // We have a template parameter list with no corresponding scope, which + // means that the resulting template declaration can't be instantiated + // properly (we'll end up with dependent nodes when we shouldn't). + if (!AllExplicitSpecHeaders) + Invalid = true; } + // C++ [temp.expl.spec]p16: + // In an explicit specialization declaration for a member of a class + // template or a member template that ap- pears in namespace scope, the + // member template and some of its enclosing class templates may remain + // unspecialized, except that the declaration shall not explicitly + // specialize a class member template if its en- closing class templates + // are not explicitly specialized as well. + if (ParamLists[NumParamLists - 1]->size() == 0 && + SawNonEmptyTemplateParameterList) { + Diag(DeclLoc, diag::err_specialize_member_of_template) + << ParamLists[ParamIdx]->getSourceRange(); + Invalid = true; + IsExplicitSpecialization = false; + return 0; + } + // Return the last template parameter list, which corresponds to the // entity being declared. return ParamLists[NumParamLists - 1]; @@ -1655,7 +1835,8 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) { Diag(Template->getLocation(), diag::note_template_declared_here) << (isa<FunctionTemplateDecl>(Template)? 0 : isa<ClassTemplateDecl>(Template)? 1 - : 2) + : isa<TypeAliasTemplateDecl>(Template)? 2 + : 3) << Template->getDeclName(); return; } @@ -1675,13 +1856,24 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) { QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { + DependentTemplateName *DTN = Name.getAsDependentTemplateName(); + if (DTN && DTN->isIdentifier()) + // When building a template-id where the template-name is dependent, + // assume the template is a type template. Either our assumption is + // correct, or the code is ill-formed and will be diagnosed when the + // dependent name is substituted. + return Context.getDependentTemplateSpecializationType(ETK_None, + DTN->getQualifier(), + DTN->getIdentifier(), + TemplateArgs); + TemplateDecl *Template = Name.getAsTemplateDecl(); if (!Template || isa<FunctionTemplateDecl>(Template)) { // We might have a substituted template template parameter pack. If so, // build a template specialization type for it. if (Name.getAsSubstTemplateTemplateParmPack()) return Context.getTemplateSpecializationType(Name, TemplateArgs); - + Diag(TemplateLoc, diag::err_template_id_not_a_type) << Name; NoteAllFoundTemplates(Name); @@ -1700,9 +1892,32 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, QualType CanonType; - if (Name.isDependent() || - TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs)) { + if (TypeAliasTemplateDecl *AliasTemplate + = dyn_cast<TypeAliasTemplateDecl>(Template)) { + // Find the canonical type for this type alias template specialization. + TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl(); + if (Pattern->isInvalidDecl()) + return QualType(); + + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Converted.data(), Converted.size()); + + // Only substitute for the innermost template argument list. + MultiLevelTemplateArgumentList TemplateArgLists; + TemplateArgLists.addOuterTemplateArguments(&TemplateArgs); + unsigned Depth = AliasTemplate->getTemplateParameters()->getDepth(); + for (unsigned I = 0; I < Depth; ++I) + TemplateArgLists.addOuterTemplateArguments(0, 0); + + InstantiatingTemplate Inst(*this, TemplateLoc, Template); + CanonType = SubstType(Pattern->getUnderlyingType(), + TemplateArgLists, AliasTemplate->getLocation(), + AliasTemplate->getDeclName()); + if (CanonType.isNull()) + return QualType(); + } else if (Name.isDependent() || + TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs)) { // This class template specialization is a dependent // type. Therefore, its canonical type is another class template // specialization type that contains all of the converted @@ -1894,6 +2109,16 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); } + + if (TypeAliasTemplateDecl *TAT = + dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) { + // C++0x [dcl.type.elab]p2: + // If the identifier resolves to a typedef-name or the simple-template-id + // resolves to an alias template specialization, the + // elaborated-type-specifier is ill-formed. + Diag(TemplateLoc, diag::err_tag_reference_non_tag) << 4; + Diag(TAT->getLocation(), diag::note_declared_at); + } QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); if (Result.isNull()) @@ -1906,7 +2131,8 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, IdentifierInfo *Id = D->getIdentifier(); assert(Id && "templated class must have an identifier"); - if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) { + if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TUK_Definition, + TagLoc, *Id)) { Diag(TagLoc, diag::err_use_with_wrong_tag) << Result << FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName()); @@ -2485,7 +2711,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, } // We have a template argument that actually does refer to a class - // template, template alias, or template template parameter, and + // template, alias template, or template template parameter, and // therefore cannot be a non-type template argument. Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr) << Arg.getSourceRange(); @@ -2562,7 +2788,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, case TemplateArgument::Type: // We have a template template parameter but the template // argument does not refer to a template. - Diag(Arg.getLocation(), diag::err_template_arg_must_be_template); + Diag(Arg.getLocation(), diag::err_template_arg_must_be_template) + << getLangOptions().CPlusPlus0x; return true; case TemplateArgument::Declaration: @@ -2631,9 +2858,6 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, unsigned ArgIdx = 0; LocalInstantiationScope InstScope(*this, true); while (Param != ParamEnd) { - if (ArgIdx > NumArgs && PartialTemplateArgs) - break; - if (ArgIdx < NumArgs) { // If we have an expanded parameter pack, make sure we don't have too // many arguments. @@ -2674,11 +2898,31 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, continue; } + // If we're checking a partial template argument list, we're done. + if (PartialTemplateArgs) { + if ((*Param)->isTemplateParameterPack() && !ArgumentPack.empty()) + Converted.push_back(TemplateArgument::CreatePackCopy(Context, + ArgumentPack.data(), + ArgumentPack.size())); + + return Invalid; + } + // If we have a template parameter pack with no more corresponding // arguments, just break out now and we'll fill in the argument pack below. if ((*Param)->isTemplateParameterPack()) break; + // If our template is a template template parameter that hasn't acquired + // its proper context yet (e.g., because we're using the template template + // parameter in the signature of a function template, before we've built + // the function template itself), don't attempt substitution of default + // template arguments at this point: we don't have enough context to + // do it properly. + if (isTemplateTemplateParameter && + Template->getDeclContext()->isTranslationUnit()) + break; + // We have a default template argument that we will use. TemplateArgumentLoc Arg; @@ -2689,7 +2933,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // the default argument. if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { if (!TTP->hasDefaultArgument()) { - assert((Invalid || PartialTemplateArgs) && "Missing default argument"); + assert(Invalid && "Missing default argument"); break; } @@ -2707,7 +2951,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { if (!NTTP->hasDefaultArgument()) { - assert((Invalid || PartialTemplateArgs) && "Missing default argument"); + assert(Invalid && "Missing default argument"); break; } @@ -2726,7 +2970,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, = cast<TemplateTemplateParmDecl>(*Param); if (!TempParm->hasDefaultArgument()) { - assert((Invalid || PartialTemplateArgs) && "Missing default argument"); + assert(Invalid && "Missing default argument"); break; } @@ -2772,9 +3016,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // in arguments for non-template parameter packs. if ((*Param)->isTemplateParameterPack()) { - if (PartialTemplateArgs && ArgumentPack.empty()) { - Converted.push_back(TemplateArgument()); - } else if (ArgumentPack.empty()) + if (ArgumentPack.empty()) Converted.push_back(TemplateArgument(0, 0)); else { Converted.push_back(TemplateArgument::CreatePackCopy(Context, @@ -2918,6 +3160,11 @@ bool UnnamedLocalNoLinkageFinder::VisitDecltypeType(const DecltypeType*) { return false; } +bool UnnamedLocalNoLinkageFinder::VisitUnaryTransformType( + const UnaryTransformType*) { + return false; +} + bool UnnamedLocalNoLinkageFinder::VisitAutoType(const AutoType *T) { return Visit(T->getDeducedType()); } @@ -3501,32 +3748,49 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return ExprError(); } + // Add the value of this argument to the list of converted + // arguments. We use the bitwidth and signedness of the template + // parameter. + if (Arg->isValueDependent()) { + // The argument is value-dependent. Create a new + // TemplateArgument with the converted expression. + Converted = TemplateArgument(Arg); + return Owned(Arg); + } + QualType IntegerType = Context.getCanonicalType(ParamType); if (const EnumType *Enum = IntegerType->getAs<EnumType>()) IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType()); - if (!Arg->isValueDependent()) { + if (ParamType->isBooleanType()) { + // Value must be zero or one. + Value = Value != 0; + unsigned AllowedBits = Context.getTypeSize(IntegerType); + if (Value.getBitWidth() != AllowedBits) + Value = Value.extOrTrunc(AllowedBits); + Value.setIsSigned(IntegerType->isSignedIntegerOrEnumerationType()); + } else { llvm::APSInt OldValue = Value; - + // Coerce the template argument's value to the value it will have // based on the template parameter's type. unsigned AllowedBits = Context.getTypeSize(IntegerType); if (Value.getBitWidth() != AllowedBits) Value = Value.extOrTrunc(AllowedBits); - Value.setIsSigned(IntegerType->isSignedIntegerType()); - + Value.setIsSigned(IntegerType->isSignedIntegerOrEnumerationType()); + // Complain if an unsigned parameter received a negative value. - if (IntegerType->isUnsignedIntegerType() - && (OldValue.isSigned() && OldValue.isNegative())) { + if (IntegerType->isUnsignedIntegerOrEnumerationType() + && (OldValue.isSigned() && OldValue.isNegative())) { Diag(Arg->getSourceRange().getBegin(), diag::warn_template_arg_negative) << OldValue.toString(10) << Value.toString(10) << Param->getType() << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); } - + // Complain if we overflowed the template parameter's type. unsigned RequiredBits; - if (IntegerType->isUnsignedIntegerType()) + if (IntegerType->isUnsignedIntegerOrEnumerationType()) RequiredBits = OldValue.getActiveBits(); else if (OldValue.isUnsigned()) RequiredBits = OldValue.getActiveBits() + 1; @@ -3541,16 +3805,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } } - // Add the value of this argument to the list of converted - // arguments. We use the bitwidth and signedness of the template - // parameter. - if (Arg->isValueDependent()) { - // The argument is value-dependent. Create a new - // TemplateArgument with the converted expression. - Converted = TemplateArgument(Arg); - return Owned(Arg); - } - Converted = TemplateArgument(Value, ParamType->isEnumeralType() ? ParamType : IntegerType); @@ -3563,10 +3817,17 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // from a template argument of type std::nullptr_t to a non-type // template parameter of type pointer to object, pointer to // function, or pointer-to-member, respectively. - if (ArgType->isNullPtrType() && - (ParamType->isPointerType() || ParamType->isMemberPointerType())) { - Converted = TemplateArgument((NamedDecl *)0); - return Owned(Arg); + if (ArgType->isNullPtrType()) { + if (ParamType->isPointerType() || ParamType->isMemberPointerType()) { + Converted = TemplateArgument((NamedDecl *)0); + return Owned(Arg); + } + + if (ParamType->isNullPtrType()) { + llvm::APSInt Zero(Context.getTypeSize(Context.NullPtrTy), true); + Converted = TemplateArgument(Zero, Context.NullPtrTy); + return Owned(Arg); + } } // Handle pointer-to-function, reference-to-function, and @@ -3715,9 +3976,10 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, return false; } - // C++ [temp.arg.template]p1: + // C++0x [temp.arg.template]p1: // A template-argument for a template template-parameter shall be - // the name of a class template, expressed as id-expression. Only + // the name of a class template or an alias template, expressed as an + // id-expression. When the template-argument names a class template, only // primary class templates are considered when matching the // template template argument with the corresponding parameter; // partial specializations are not considered even if their @@ -3727,7 +3989,8 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, // will happen when we are dealing with, e.g., class template // partial specializations. if (!isa<ClassTemplateDecl>(Template) && - !isa<TemplateTemplateParmDecl>(Template)) { + !isa<TemplateTemplateParmDecl>(Template) && + !isa<TypeAliasTemplateDecl>(Template)) { assert(isa<FunctionTemplateDecl>(Template) && "Only function templates are possible here"); Diag(Arg.getLocation(), diag::err_template_arg_not_class_template); @@ -3858,6 +4121,9 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, Arg.getAsIntegral()->getBoolValue(), T, Loc)); + if (T->isNullPtrType()) + return Owned(new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc)); + // If this is an enum type that we're instantiating, we need to use an integer // type the same size as the enumerator. We don't want to build an // IntegerLiteral with enum type. @@ -4044,7 +4310,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, // C++0x [temp.arg.template]p3: // A template-argument matches a template template-parameter (call it P) // when each of the template parameters in the template-parameter-list of - // the template-argument's corresponding class template or template alias + // the template-argument's corresponding class template or alias template // (call it A) matches the corresponding template parameter in the // template-parameter-list of P. [...] TemplateParameterList::iterator NewParm = New->begin(); @@ -4442,7 +4708,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // friend declarations. bool Invalid = false; TemplateParameterList *TemplateParams - = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS, + = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, + TemplateNameLoc, + SS, (TemplateParameterList**)TemplateParameterLists.get(), TemplateParameterLists.size(), TUK == TUK_Friend, @@ -4509,7 +4777,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); assert(Kind != TTK_Enum && "Invalid enum tag in class template spec!"); if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), - Kind, KWLoc, + Kind, TUK == TUK_Definition, KWLoc, *ClassTemplate->getIdentifier())) { Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate @@ -5180,7 +5448,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, SpecInfo->getPointOfInstantiation(), HasNoEffect)) return true; - + // Mark the prior declaration as an explicit specialization, so that later // clients know that this is an explicit specialization. if (!isFriend) { @@ -5200,7 +5468,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, TemplArgs, /*InsertPos=*/0, SpecInfo->getTemplateSpecializationKind(), TemplArgsAsWritten); - + FD->setStorageClass(Specialization->getStorageClass()); + // The "previous declaration" for this function template specialization is // the prior function template specialization. Previous.clear(); @@ -5479,7 +5748,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, assert(Kind != TTK_Enum && "Invalid enum tag in class template explicit instantiation!"); if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), - Kind, KWLoc, + Kind, /*isDefinition*/false, KWLoc, *ClassTemplate->getIdentifier())) { Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate @@ -5801,11 +6070,20 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (R.isNull()) return true; + // C++ [dcl.stc]p1: + // A storage-class-specifier shall not be specified in [...] an explicit + // instantiation (14.7.2) directive. if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { - // Cannot explicitly instantiate a typedef. Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_of_typedef) << Name; return true; + } else if (D.getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_unspecified) { + // Complain about then remove the storage class specifier. + Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_storage_class) + << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); + + D.getMutableDeclSpec().ClearStorageClassSpecs(); } // C++0x [temp.explicit]p1: diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 235af04..7d0ce8b 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -2314,7 +2314,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, FunctionTemplate->getLocation(), FunctionTemplate->getSourceRange().getEnd(), 0, Builder, - CTAK_Deduced)) { + CTAK_Specified)) { Info.Param = makeTemplateParameter( const_cast<NamedDecl *>(TemplateParams->getParam(I))); // FIXME: These template arguments are temporary. Free them! @@ -2500,6 +2500,12 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S, if (ParamRefType) { QualType PointeeType = ParamRefType->getPointeeType(); + // If the argument has incomplete array type, try to complete it's type. + if (ArgType->isIncompleteArrayType() && + !S.RequireCompleteExprType(Arg, S.PDiag(), + std::make_pair(SourceLocation(), S.PDiag()))) + ArgType = Arg->getType(); + // [C++0x] If P is an rvalue reference to a cv-unqualified // template parameter and the argument is an lvalue, the type // "lvalue reference to A" is used in place of A for type @@ -2507,7 +2513,9 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S, if (isa<RValueReferenceType>(ParamType)) { if (!PointeeType.getQualifiers() && isa<TemplateTypeParmType>(PointeeType) && - Arg->Classify(S.Context).isLValue()) + Arg->Classify(S.Context).isLValue() && + Arg->getType() != S.Context.OverloadTy && + Arg->getType() != S.Context.BoundMemberTy) ArgType = S.Context.getLValueReferenceType(ArgType); } @@ -3884,6 +3892,13 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, OnlyDeduced, Depth, Used); break; + case Type::UnaryTransform: + if (!OnlyDeduced) + MarkUsedTemplateParameters(SemaRef, + cast<UnaryTransformType>(T)->getUnderlyingType(), + OnlyDeduced, Depth, Used); + break; + case Type::PackExpansion: MarkUsedTemplateParameters(SemaRef, cast<PackExpansionType>(T)->getPattern(), diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 92ba095..3c19641 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -13,6 +13,7 @@ #include "clang/Sema/SemaInternal.h" #include "TreeTransform.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" @@ -58,9 +59,13 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, Result.addOuterTemplateArguments(Innermost); DeclContext *Ctx = dyn_cast<DeclContext>(D); - if (!Ctx) + if (!Ctx) { Ctx = D->getDeclContext(); - + + assert((!D->isTemplateParameter() || !Ctx->isTranslationUnit()) && + "Template parameter doesn't have its context yet!"); + } + while (!Ctx->isFileContext()) { // Add template arguments from a class template instantiation. if (ClassTemplateSpecializationDecl *Spec @@ -446,10 +451,15 @@ void Sema::PrintInstantiationStack() { Diags.Report(Active->PointOfInstantiation, DiagID) << Function << Active->InstantiationRange; - } else { + } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) { Diags.Report(Active->PointOfInstantiation, diag::note_template_static_data_member_def_here) - << cast<VarDecl>(D) + << VD + << Active->InstantiationRange; + } else { + Diags.Report(Active->PointOfInstantiation, + diag::note_template_type_alias_instantiation_here) + << cast<TypeAliasTemplateDecl>(D) << Active->InstantiationRange; } break; @@ -918,7 +928,8 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc, // like it's likely to produce a lot of spurious errors. if (Keyword != ETK_None && Keyword != ETK_Typename) { TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword); - if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, TagLocation, *Id)) { + if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, /*isDefinition*/false, + TagLocation, *Id)) { SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag) << Id << FixItHint::CreateReplacement(SourceRange(TagLocation), @@ -968,8 +979,7 @@ TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS, } TemplateName Template = Arg.getAsTemplate(); - assert(!Template.isNull() && Template.getAsTemplateDecl() && - "Wrong kind of template template argument"); + assert(!Template.isNull() && "Null template template argument"); // We don't ever want to substitute for a qualified template name, since // the qualifier is handled separately. So, look through the qualified @@ -1384,6 +1394,12 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { for (unsigned I = 0, E = FP.getNumArgs(); I != E; ++I) { ParmVarDecl *P = FP.getArg(I); + // The parameter's type as written might be dependent even if the + // decayed type was not dependent. + if (TypeSourceInfo *TSInfo = P->getTypeSourceInfo()) + if (TSInfo->getType()->isDependentType()) + return true; + // TODO: currently we always rebuild expressions. When we // properly get lazier about this, we should use the same // logic to avoid rebuilding prototypes here. @@ -1729,6 +1745,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs); llvm::SmallVector<Decl*, 4> Fields; + llvm::SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4> + FieldsWithMemberInitializers; for (RecordDecl::decl_iterator Member = Pattern->decls_begin(), MemberEnd = Pattern->decls_end(); Member != MemberEnd; ++Member) { @@ -1751,9 +1769,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Decl *NewMember = Instantiator.Visit(*Member); if (NewMember) { - if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) + if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) { Fields.push_back(Field); - else if (NewMember->isInvalidDecl()) + FieldDecl *OldField = cast<FieldDecl>(*Member); + if (OldField->getInClassInitializer()) + FieldsWithMemberInitializers.push_back(std::make_pair(OldField, + Field)); + } else if (NewMember->isInvalidDecl()) Invalid = true; } else { // FIXME: Eventually, a NULL return will mean that one of the @@ -1767,6 +1789,43 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Fields.data(), Fields.size(), SourceLocation(), SourceLocation(), 0); 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 = SubstExpr(OldInit, TemplateArgs); + + // If the initialization is no longer dependent, check it now. + if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent()) + && !NewField->getType()->isDependentType() + && !NewInit.get()->isTypeDependent()) { + // FIXME: handle list-initialization + SourceLocation EqualLoc = NewField->getLocation(); + NewInit = PerformCopyInitialization( + InitializedEntity::InitializeMember(NewField), EqualLoc, + NewInit.release()); + + if (!NewInit.isInvalid()) { + CheckImplicitConversions(NewInit.get(), EqualLoc); + + // C++0x [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + NewInit = MaybeCreateExprWithCleanups(NewInit); + } + } + + if (NewInit.isInvalid()) + NewField->setInvalidDecl(); + else + NewField->setInClassInitializer(NewInit.release()); + } + + if (!FieldsWithMemberInitializers.empty()) + ActOnFinishDelayedMemberInitializers(Instantiation); + if (Instantiation->isInvalidDecl()) Invalid = true; else { @@ -2009,7 +2068,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, SuppressNew) continue; - if (Function->hasBody()) + if (Function->isDefined()) continue; if (TSK == TSK_ExplicitInstantiationDefinition) { @@ -2019,7 +2078,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, // specialization and is only an explicit instantiation definition // of members whose definition is visible at the point of // instantiation. - if (!Pattern->hasBody()) + if (!Pattern->isDefined()) continue; Function->setTemplateSpecializationKind(TSK, PointOfInstantiation); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 6e11ef5..e78aa29 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -128,8 +128,8 @@ TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { return Inst; } -Decl *TemplateDeclInstantiator::VisitTypedefNameDecl(TypedefNameDecl *D, - bool IsTypeAlias) { +Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D, + bool IsTypeAlias) { bool Invalid = false; TypeSourceInfo *DI = D->getTypeSourceInfo(); if (DI->getType()->isDependentType() || @@ -178,17 +178,62 @@ Decl *TemplateDeclInstantiator::VisitTypedefNameDecl(TypedefNameDecl *D, SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef); Typedef->setAccess(D->getAccess()); - Owner->addDecl(Typedef); return Typedef; } Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { - return VisitTypedefNameDecl(D, /*IsTypeAlias=*/false); + Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/false); + Owner->addDecl(Typedef); + return Typedef; } Decl *TemplateDeclInstantiator::VisitTypeAliasDecl(TypeAliasDecl *D) { - return VisitTypedefNameDecl(D, /*IsTypeAlias=*/true); + Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/true); + Owner->addDecl(Typedef); + return Typedef; +} + +Decl * +TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { + // Create a local instantiation scope for this type alias template, which + // will contain the instantiations of the template parameters. + LocalInstantiationScope Scope(SemaRef); + + TemplateParameterList *TempParams = D->getTemplateParameters(); + TemplateParameterList *InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return 0; + + TypeAliasDecl *Pattern = D->getTemplatedDecl(); + + TypeAliasTemplateDecl *PrevAliasTemplate = 0; + if (Pattern->getPreviousDeclaration()) { + DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName()); + if (Found.first != Found.second) { + PrevAliasTemplate = dyn_cast<TypeAliasTemplateDecl>(*Found.first); + } + } + + TypeAliasDecl *AliasInst = cast_or_null<TypeAliasDecl>( + InstantiateTypedefNameDecl(Pattern, /*IsTypeAlias=*/true)); + if (!AliasInst) + return 0; + + TypeAliasTemplateDecl *Inst + = TypeAliasTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getDeclName(), InstParams, AliasInst); + if (PrevAliasTemplate) + Inst->setPreviousDeclaration(PrevAliasTemplate); + + Inst->setAccess(D->getAccess()); + + if (!PrevAliasTemplate) + Inst->setInstantiatedFromMemberTemplate(D); + + Owner->addDecl(Inst); + + return Inst; } /// \brief Instantiate an initializer, breaking it into separate @@ -432,6 +477,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { D->getLocation(), D->isMutable(), BitWidth, + D->hasInClassInitializer(), D->getTypeSpecStartLoc(), D->getAccess(), 0); @@ -1171,7 +1217,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, D->isThisDeclarationADefinition()) { // Check for a function body. const FunctionDecl *Definition = 0; - if (Function->hasBody(Definition) && + if (Function->isDefined(Definition) && Definition->getTemplateSpecializationKind() == TSK_Undeclared) { SemaRef.Diag(Function->getLocation(), diag::err_redefinition) << Function->getDeclName(); @@ -1203,7 +1249,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, default: if (const FunctionDecl *RPattern = R->getTemplateInstantiationPattern()) - if (RPattern->hasBody(RPattern)) { + if (RPattern->isDefined(RPattern)) { SemaRef.Diag(Function->getLocation(), diag::err_redefinition) << Function->getDeclName(); SemaRef.Diag(R->getLocation(), diag::note_previous_definition); @@ -1219,6 +1265,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) PrincipalDecl->setNonMemberOperator(); + assert(!D->isDefaulted() && "only methods should be defaulted"); return Function; } @@ -1451,7 +1498,14 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, else Owner->addDecl(DeclToAdd); } - + + if (D->isExplicitlyDefaulted()) { + SemaRef.SetDeclDefaulted(Method, Method->getLocation()); + } else { + assert(!D->isDefaulted() && + "should not implicitly default uninstantiated function"); + } + return Method; } @@ -2079,8 +2133,8 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, bool TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl) { - if (Tmpl->isDeleted()) - New->setDeleted(); + if (Tmpl->isDeletedAsWritten()) + New->setDeletedAsWritten(); // If we are performing substituting explicitly-specified template arguments // or deduced template arguments into a function template and we reach this @@ -2186,6 +2240,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, } Expr *NoexceptExpr = 0; if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) { + EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs); if (E.isUsable()) NoexceptExpr = E.take(); @@ -2255,7 +2310,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive, bool DefinitionRequired) { - if (Function->isInvalidDecl() || Function->hasBody()) + if (Function->isInvalidDecl() || Function->isDefined()) return; // Never instantiate an explicit specialization. @@ -2264,12 +2319,19 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Find the function body that we'll be substituting. const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern(); - Stmt *Pattern = 0; - if (PatternDecl) - Pattern = PatternDecl->getBody(PatternDecl); + assert(PatternDecl && "instantiating a non-template"); + + Stmt *Pattern = PatternDecl->getBody(PatternDecl); + assert(PatternDecl && "template definition is not a template"); + if (!Pattern) { + // Try to find a defaulted definition + PatternDecl->isDefined(PatternDecl); + } + assert(PatternDecl && "template definition is not a template"); // Postpone late parsed template instantiations. - if (PatternDecl->isLateTemplateParsed() && !LateTemplateParser) { + if (PatternDecl->isLateTemplateParsed() && + !LateTemplateParser) { PendingInstantiations.push_back( std::make_pair(Function, PointOfInstantiation)); return; @@ -2277,13 +2339,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Call the LateTemplateParser callback if there a need to late parse // a templated function definition. - if (!Pattern && PatternDecl && PatternDecl->isLateTemplateParsed() && + if (!Pattern && PatternDecl->isLateTemplateParsed() && LateTemplateParser) { LateTemplateParser(OpaqueParser, PatternDecl); Pattern = PatternDecl->getBody(PatternDecl); } - if (!Pattern) { + if (!Pattern && !PatternDecl->isDefaulted()) { if (DefinitionRequired) { if (Function->getPrimaryTemplate()) Diag(PointOfInstantiation, @@ -2378,21 +2440,27 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(Function, 0, false, PatternDecl); - // If this is a constructor, instantiate the member initializers. - if (const CXXConstructorDecl *Ctor = - dyn_cast<CXXConstructorDecl>(PatternDecl)) { - InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor, - TemplateArgs); - } + if (PatternDecl->isDefaulted()) { + ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true); - // Instantiate the function body. - StmtResult Body = SubstStmt(Pattern, TemplateArgs); + SetDeclDefaulted(Function, PatternDecl->getLocation()); + } else { + // If this is a constructor, instantiate the member initializers. + if (const CXXConstructorDecl *Ctor = + dyn_cast<CXXConstructorDecl>(PatternDecl)) { + InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor, + TemplateArgs); + } - if (Body.isInvalid()) - Function->setInvalidDecl(); - - ActOnFinishFunctionBody(Function, Body.get(), - /*IsInstantiation=*/true); + // Instantiate the function body. + StmtResult Body = SubstStmt(Pattern, TemplateArgs); + + if (Body.isInvalid()) + Function->setInvalidDecl(); + + ActOnFinishFunctionBody(Function, Body.get(), + /*IsInstantiation=*/true); + } PerformDependentDiagnostics(PatternDecl, TemplateArgs); @@ -2415,9 +2483,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, PerformPendingInstantiations(); // Restore the set of pending vtables. + assert(VTableUses.empty() && + "VTableUses should be empty before it is discarded."); VTableUses.swap(SavedVTableUses); // Restore the set of pending implicit instantiations. + assert(PendingInstantiations.empty() && + "PendingInstantiations should be empty before it is discarded."); PendingInstantiations.swap(SavedPendingInstantiations); } } @@ -2484,6 +2556,10 @@ void Sema::InstantiateStaticDataMemberDefinition( == TSK_ExplicitInstantiationDeclaration) return; + // If we already have a definition, we're done. + if (Var->getDefinition()) + return; + InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); if (Inst) return; @@ -2491,9 +2567,12 @@ void Sema::InstantiateStaticDataMemberDefinition( // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate later, // while we're still within our own instantiation context. + llvm::SmallVector<VTableUse, 16> SavedVTableUses; std::deque<PendingImplicitInstantiation> SavedPendingInstantiations; - if (Recursive) + if (Recursive) { + VTableUses.swap(SavedVTableUses); PendingInstantiations.swap(SavedPendingInstantiations); + } // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. @@ -2515,11 +2594,23 @@ void Sema::InstantiateStaticDataMemberDefinition( } if (Recursive) { + // Define any newly required vtables. + DefineUsedVTables(); + // Instantiate any pending implicit instantiations found during the // instantiation of this template. PerformPendingInstantiations(); + // Restore the set of pending vtables. + assert(VTableUses.empty() && + "VTableUses should be empty before it is discarded, " + "while instantiating static data member."); + VTableUses.swap(SavedVTableUses); + // Restore the set of pending implicit instantiations. + assert(PendingInstantiations.empty() && + "PendingInstantiations should be empty before it is discarded, " + "while instantiating static data member."); PendingInstantiations.swap(SavedPendingInstantiations); } } @@ -3115,10 +3206,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, /// \brief Performs template instantiation for all implicit template /// instantiations we have seen until this point. -/// -/// \returns true if anything was instantiated. -bool Sema::PerformPendingInstantiations(bool LocalOnly) { - bool InstantiatedAnything = false; +void Sema::PerformPendingInstantiations(bool LocalOnly) { while (!PendingLocalImplicitInstantiations.empty() || (!LocalOnly && !PendingInstantiations.empty())) { PendingImplicitInstantiation Inst; @@ -3139,7 +3227,6 @@ bool Sema::PerformPendingInstantiations(bool LocalOnly) { TSK_ExplicitInstantiationDefinition; InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true, DefinitionRequired); - InstantiatedAnything = true; continue; } @@ -3176,10 +3263,7 @@ bool Sema::PerformPendingInstantiations(bool LocalOnly) { TSK_ExplicitInstantiationDefinition; InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true, DefinitionRequired); - InstantiatedAnything = true; } - - return InstantiatedAnything; } void Sema::PerformDependentDiagnostics(const DeclContext *Pattern, diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 096d353..86d3bc1 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -617,7 +617,8 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { const DeclSpec &DS = D.getDeclSpec(); switch (DS.getTypeSpecType()) { case TST_typename: - case TST_typeofType: { + case TST_typeofType: + case TST_underlyingType: { QualType T = DS.getRepAsType().get(); if (!T.isNull() && T->containsUnexpandedParameterPack()) return true; diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 00ac1d6..5fd8afa 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -15,6 +15,7 @@ #include "clang/Sema/Template.h" #include "clang/Basic/OpenCL.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTMutationListener.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -836,6 +837,18 @@ static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) { } break; } + case DeclSpec::TST_underlyingType: + Result = S.GetTypeFromParser(DS.getRepAsType()); + assert(!Result.isNull() && "Didn't get a type for __underlying_type?"); + Result = S.BuildUnaryTransformType(Result, + UnaryTransformType::EnumUnderlyingType, + DS.getTypeSpecTypeLoc()); + if (Result.isNull()) { + Result = Context.IntTy; + declarator.setInvalidType(true); + } + break; + case DeclSpec::TST_auto: { // TypeQuals handled by caller. Result = Context.getAutoType(QualType()); @@ -1048,6 +1061,9 @@ QualType Sema::BuildPointerType(QualType T, QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, SourceLocation Loc, DeclarationName Entity) { + assert(Context.getCanonicalType(T) != Context.OverloadTy && + "Unresolved overloaded function type"); + // C++0x [dcl.ref]p6: // If a typedef (7.1.3), a type template-parameter (14.3.1), or a // decltype-specifier (7.1.6.2) denotes a type TR that is a reference to a @@ -1464,41 +1480,37 @@ static void DiagnoseIgnoredQualifiers(unsigned Quals, FixItHint VolatileFixIt; FixItHint RestrictFixIt; + const SourceManager &SM = S.getSourceManager(); + // FIXME: The locations here are set kind of arbitrarily. It'd be nicer to // find a range and grow it to encompass all the qualifiers, regardless of // the order in which they textually appear. if (Quals & Qualifiers::Const) { ConstFixIt = FixItHint::CreateRemoval(ConstQualLoc); - Loc = ConstQualLoc; - ++NumQuals; QualStr = "const"; + ++NumQuals; + if (!Loc.isValid() || SM.isBeforeInTranslationUnit(ConstQualLoc, Loc)) + Loc = ConstQualLoc; } if (Quals & Qualifiers::Volatile) { VolatileFixIt = FixItHint::CreateRemoval(VolatileQualLoc); - if (NumQuals == 0) { - Loc = VolatileQualLoc; - QualStr = "volatile"; - } else { - QualStr += " volatile"; - } + QualStr += (NumQuals == 0 ? "volatile" : " volatile"); ++NumQuals; + if (!Loc.isValid() || SM.isBeforeInTranslationUnit(VolatileQualLoc, Loc)) + Loc = VolatileQualLoc; } if (Quals & Qualifiers::Restrict) { RestrictFixIt = FixItHint::CreateRemoval(RestrictQualLoc); - if (NumQuals == 0) { - Loc = RestrictQualLoc; - QualStr = "restrict"; - } else { - QualStr += " restrict"; - } + QualStr += (NumQuals == 0 ? "restrict" : " restrict"); ++NumQuals; + if (!Loc.isValid() || SM.isBeforeInTranslationUnit(RestrictQualLoc, Loc)) + Loc = RestrictQualLoc; } assert(NumQuals > 0 && "No known qualifiers?"); S.Diag(Loc, diag::warn_qual_return_type) - << QualStr << NumQuals - << ConstFixIt << VolatileFixIt << RestrictFixIt; + << QualStr << NumQuals << ConstFixIt << VolatileFixIt << RestrictFixIt; } /// GetTypeForDeclarator - Convert the type for the specified @@ -1581,6 +1593,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, Error = 0; // Function prototype break; case Declarator::MemberContext: + if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) + break; switch (cast<TagDecl>(CurContext)->getTagKind()) { case TTK_Enum: assert(0 && "unhandled tag kind"); break; case TTK_Struct: Error = 1; /* Struct member */ break; @@ -1601,6 +1615,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, Error = 7; // Template type argument break; case Declarator::AliasDeclContext: + case Declarator::AliasTemplateContext: Error = 9; // Type alias break; case Declarator::TypeNameContext: @@ -1659,7 +1674,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // Does this declaration declare a typedef-name? bool IsTypedefName = D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef || - D.getContext() == Declarator::AliasDeclContext; + D.getContext() == Declarator::AliasDeclContext || + D.getContext() == Declarator::AliasTemplateContext; // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is @@ -1839,7 +1855,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // anyway. if (IsTypedefName && FTI.getExceptionSpecType()) Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef) - << (D.getContext() == Declarator::AliasDeclContext); + << (D.getContext() == Declarator::AliasDeclContext || + D.getContext() == Declarator::AliasTemplateContext); if (!FTI.NumArgs && !FTI.isVariadic && !getLangOptions().CPlusPlus) { // Simple void foo(), where the incoming T is the result type. @@ -2204,6 +2221,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here? case Declarator::TypeNameContext: case Declarator::AliasDeclContext: + case Declarator::AliasTemplateContext: case Declarator::MemberContext: case Declarator::BlockContext: case Declarator::ForContext: @@ -2367,6 +2385,16 @@ namespace { Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); TL.setUnderlyingTInfo(TInfo); } + void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { + // FIXME: This holds only because we only have one unary transform. + assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType); + TL.setKWLoc(DS.getTypeSpecTypeLoc()); + TL.setParensRange(DS.getTypeofParensRange()); + assert(DS.getRepAsType()); + TypeSourceInfo *TInfo = 0; + Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); + TL.setUnderlyingTInfo(TInfo); + } void VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { // By default, use the source location of the type specifier. TL.setBuiltinLoc(DS.getTypeSpecTypeLoc()); @@ -2640,13 +2668,17 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { CheckExtraCXXDefaultArguments(D); // C++0x [dcl.type]p3: - // A type-specifier-seq shall not define a class or enumeration - // unless it appears in the type-id of an alias-declaration - // (7.1.3). - if (OwnedTag && OwnedTag->isDefinition() && - D.getContext() != Declarator::AliasDeclContext) - Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier) - << Context.getTypeDeclType(OwnedTag); + // A type-specifier-seq shall not define a class or enumeration unless + // it appears in the type-id of an alias-declaration (7.1.3) that is not + // the declaration of a template-declaration. + if (OwnedTag && OwnedTag->isDefinition()) { + if (D.getContext() == Declarator::AliasTemplateContext) + Diag(OwnedTag->getLocation(), diag::err_type_defined_in_alias_template) + << Context.getTypeDeclType(OwnedTag); + else if (D.getContext() != Declarator::AliasDeclContext) + Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier) + << Context.getTypeDeclType(OwnedTag); + } } return CreateParsedType(T, TInfo); @@ -3213,6 +3245,82 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, } while ((attrs = next)); } +/// \brief Ensure that the type of the given expression is complete. +/// +/// This routine checks whether the expression \p E has a complete type. If the +/// expression refers to an instantiable construct, that instantiation is +/// performed as needed to complete its type. Furthermore +/// Sema::RequireCompleteType is called for the expression's type (or in the +/// case of a reference type, the referred-to type). +/// +/// \param E The expression whose type is required to be complete. +/// \param PD The partial diagnostic that will be printed out if the type cannot +/// be completed. +/// +/// \returns \c true if the type of \p E is incomplete and diagnosed, \c false +/// otherwise. +bool Sema::RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD, + std::pair<SourceLocation, + PartialDiagnostic> Note) { + QualType T = E->getType(); + + // Fast path the case where the type is already complete. + if (!T->isIncompleteType()) + return false; + + // Incomplete array types may be completed by the initializer attached to + // their definitions. For static data members of class templates we need to + // instantiate the definition to get this initializer and complete the type. + if (T->isIncompleteArrayType()) { + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) { + if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) { + if (Var->isStaticDataMember() && + Var->getInstantiatedFromStaticDataMember()) { + + MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo(); + assert(MSInfo && "Missing member specialization information?"); + if (MSInfo->getTemplateSpecializationKind() + != TSK_ExplicitSpecialization) { + // If we don't already have a point of instantiation, this is it. + if (MSInfo->getPointOfInstantiation().isInvalid()) { + MSInfo->setPointOfInstantiation(E->getLocStart()); + + // This is a modification of an existing AST node. Notify + // listeners. + if (ASTMutationListener *L = getASTMutationListener()) + L->StaticDataMemberInstantiated(Var); + } + + InstantiateStaticDataMemberDefinition(E->getExprLoc(), Var); + + // Update the type to the newly instantiated definition's type both + // here and within the expression. + if (VarDecl *Def = Var->getDefinition()) { + DRE->setDecl(Def); + T = Def->getType(); + DRE->setType(T); + E->setType(T); + } + } + + // We still go on to try to complete the type independently, as it + // may also require instantiations or diagnostics if it remains + // incomplete. + } + } + } + } + + // FIXME: Are there other cases which require instantiating something other + // than the type to complete the type of an expression? + + // Look through reference types and complete the referred type. + if (const ReferenceType *Ref = T->getAs<ReferenceType>()) + T = Ref->getPointeeType(); + + return RequireCompleteType(E->getExprLoc(), T, PD, Note); +} + /// @brief Ensure that the type T is a complete type. /// /// This routine checks whether the type @p T is complete in any @@ -3363,3 +3471,27 @@ QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) { return Context.getDecltypeType(E); } + +QualType Sema::BuildUnaryTransformType(QualType BaseType, + UnaryTransformType::UTTKind UKind, + SourceLocation Loc) { + switch (UKind) { + case UnaryTransformType::EnumUnderlyingType: + if (!BaseType->isDependentType() && !BaseType->isEnumeralType()) { + Diag(Loc, diag::err_only_enums_have_underlying_types); + return QualType(); + } else { + QualType Underlying = BaseType; + if (!BaseType->isDependentType()) { + EnumDecl *ED = BaseType->getAs<EnumType>()->getDecl(); + assert(ED && "EnumType has no EnumDecl"); + DiagnoseUseOfDecl(ED, Loc); + Underlying = ED->getIntegerType(); + } + assert(!Underlying.isNull()); + return Context.getUnaryTransformType(BaseType, Underlying, + UnaryTransformType::EnumUnderlyingType); + } + } + llvm_unreachable("unknown unary transform type"); +} diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 2a71e14..ff2e46a 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -21,6 +21,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" @@ -701,6 +702,11 @@ public: /// By default, builds a new TypeOfType with the given underlying type. QualType RebuildTypeOfType(QualType Underlying); + /// \brief Build a new unary transform type. + QualType RebuildUnaryTransformType(QualType BaseType, + UnaryTransformType::UTTKind UKind, + SourceLocation Loc); + /// \brief Build a new C++0x decltype type. /// /// By default, performs semantic analysis when building the decltype type. @@ -855,7 +861,7 @@ public: case LookupResult::Found: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: { - NamedDecl *SomeDecl = Result.getRepresentativeDecl(); + NamedDecl *SomeDecl = Result.getRepresentativeDecl(); unsigned Kind = 0; if (isa<TypedefDecl>(SomeDecl)) Kind = 1; else if (isa<TypeAliasDecl>(SomeDecl)) Kind = 2; @@ -863,7 +869,7 @@ public: SemaRef.Diag(IdLoc, diag::err_tag_reference_non_tag) << Kind; SemaRef.Diag(SomeDecl->getLocation(), diag::note_declared_at); break; - } + } default: // FIXME: Would be nice to highlight just the source range. SemaRef.Diag(IdLoc, diag::err_not_tag_in_scope) @@ -873,7 +879,8 @@ public: return QualType(); } - if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, IdLoc, *Id)) { + if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, /*isDefinition*/false, + IdLoc, *Id)) { SemaRef.Diag(KeywordLoc, diag::err_use_with_wrong_tag) << Id; SemaRef.Diag(Tag->getLocation(), diag::note_previous_use); return QualType(); @@ -1372,7 +1379,7 @@ public: UnaryExprOrTypeTrait ExprKind, SourceRange R) { ExprResult Result - = getSema().CreateUnaryExprOrTypeTraitExpr(SubExpr, OpLoc, ExprKind, R); + = getSema().CreateUnaryExprOrTypeTraitExpr(SubExpr, OpLoc, ExprKind); if (Result.isInvalid()) return ExprError(); @@ -2567,9 +2574,13 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc( Q.getLocalEndLoc()); break; } - - SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag) - << TL.getType() << SS.getRange(); + // If the nested-name-specifier is an invalid type def, don't emit an + // error because a previous error should have already been emitted. + TypedefTypeLoc* TTL = dyn_cast<TypedefTypeLoc>(&TL); + if (!TTL || !TTL->getTypedefNameDecl()->isInvalidDecl()) { + SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag) + << TL.getType() << SS.getRange(); + } return NestedNameSpecifierLoc(); } } @@ -4154,6 +4165,29 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB, } template<typename Derived> +QualType TreeTransform<Derived>::TransformUnaryTransformType( + TypeLocBuilder &TLB, + UnaryTransformTypeLoc TL) { + QualType Result = TL.getType(); + if (Result->isDependentType()) { + const UnaryTransformType *T = TL.getTypePtr(); + QualType NewBase = + getDerived().TransformType(TL.getUnderlyingTInfo())->getType(); + Result = getDerived().RebuildUnaryTransformType(NewBase, + T->getUTTKind(), + TL.getKWLoc()); + if (Result.isNull()) + return QualType(); + } + + UnaryTransformTypeLoc NewTL = TLB.push<UnaryTransformTypeLoc>(Result); + NewTL.setKWLoc(TL.getKWLoc()); + NewTL.setParensRange(TL.getParensRange()); + NewTL.setUnderlyingTInfo(TL.getUnderlyingTInfo()); + return Result; +} + +template<typename Derived> QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) { const AutoType *T = TL.getTypePtr(); @@ -4389,6 +4423,23 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType( NewTemplateArgs); if (!Result.isNull()) { + // Specializations of template template parameters are represented as + // TemplateSpecializationTypes, and substitution of type alias templates + // within a dependent context can transform them into + // DependentTemplateSpecializationTypes. + if (isa<DependentTemplateSpecializationType>(Result)) { + DependentTemplateSpecializationTypeLoc NewTL + = TLB.push<DependentTemplateSpecializationTypeLoc>(Result); + NewTL.setKeywordLoc(TL.getTemplateNameLoc()); + NewTL.setQualifierLoc(NestedNameSpecifierLoc()); + NewTL.setNameLoc(TL.getTemplateNameLoc()); + NewTL.setLAngleLoc(TL.getLAngleLoc()); + NewTL.setRAngleLoc(TL.getRAngleLoc()); + for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i) + NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo()); + return Result; + } + TemplateSpecializationTypeLoc NewTL = TLB.push<TemplateSpecializationTypeLoc>(Result); NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); @@ -4478,6 +4529,23 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, if (NamedT.isNull()) return QualType(); + // C++0x [dcl.type.elab]p2: + // If the identifier resolves to a typedef-name or the simple-template-id + // resolves to an alias template specialization, the + // elaborated-type-specifier is ill-formed. + if (T->getKeyword() != ETK_None && T->getKeyword() != ETK_Typename) { + if (const TemplateSpecializationType *TST = + NamedT->getAs<TemplateSpecializationType>()) { + TemplateName Template = TST->getTemplateName(); + if (TypeAliasTemplateDecl *TAT = + dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) { + SemaRef.Diag(TL.getNamedTypeLoc().getBeginLoc(), + diag::err_tag_reference_non_tag) << 4; + SemaRef.Diag(TAT->getLocation(), diag::note_declared_at); + } + } + } + QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || QualifierLoc != TL.getQualifierLoc() || @@ -6629,8 +6697,12 @@ template<typename Derived> ExprResult TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) { DeclContext *DC = getSema().getFunctionLevelDeclContext(); - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC); - QualType T = MD->getThisType(getSema().Context); + QualType T; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) + T = MD->getThisType(getSema().Context); + else + T = getSema().Context.getPointerType( + getSema().Context.getRecordType(cast<CXXRecordDecl>(DC))); if (!getDerived().AlwaysRebuild() && T == E->getType()) return SemaRef.Owned(E); @@ -7449,6 +7521,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) template<typename Derived> ExprResult TreeTransform<Derived>::TransformCXXNoexceptExpr(CXXNoexceptExpr *E) { + EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); ExprResult SubExpr = getDerived().TransformExpr(E->getOperand()); if (SubExpr.isInvalid()) return ExprError(); @@ -7700,6 +7773,11 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { BlockScopeInfo *blockScope = SemaRef.getCurBlock(); blockScope->TheDecl->setIsVariadic(oldBlock->isVariadic()); + // We built a new blockScopeInfo in call to ActOnBlockStart + // in above, CapturesCXXThis need be set here from the block + // expression. + blockScope->CapturesCXXThis = oldBlock->capturesCXXThis(); + llvm::SmallVector<ParmVarDecl*, 4> params; llvm::SmallVector<QualType, 4> paramTypes; @@ -7759,22 +7837,21 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { #ifndef NDEBUG // In builds with assertions, make sure that we captured everything we // captured before. + if (!SemaRef.getDiagnostics().hasErrorOccurred()) { + for (BlockDecl::capture_iterator i = oldBlock->capture_begin(), + e = oldBlock->capture_end(); i != e; ++i) { + VarDecl *oldCapture = i->getVariable(); + + // Ignore parameter packs. + if (isa<ParmVarDecl>(oldCapture) && + cast<ParmVarDecl>(oldCapture)->isParameterPack()) + continue; - if (oldBlock->capturesCXXThis()) assert(blockScope->CapturesCXXThis); - - for (BlockDecl::capture_iterator i = oldBlock->capture_begin(), - e = oldBlock->capture_end(); i != e; ++i) { - VarDecl *oldCapture = i->getVariable(); - - // Ignore parameter packs. - if (isa<ParmVarDecl>(oldCapture) && - cast<ParmVarDecl>(oldCapture)->isParameterPack()) - continue; - - VarDecl *newCapture = - cast<VarDecl>(getDerived().TransformDecl(E->getCaretLocation(), - oldCapture)); - assert(blockScope->CaptureMap.count(newCapture)); + VarDecl *newCapture = + cast<VarDecl>(getDerived().TransformDecl(E->getCaretLocation(), + oldCapture)); + assert(blockScope->CaptureMap.count(newCapture)); + } } #endif @@ -7805,6 +7882,13 @@ TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) { ND, NameInfo, 0); } +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformAsTypeExpr(AsTypeExpr *E) { + assert(false && "Cannot transform asType expressions yet"); + return SemaRef.Owned(E); +} + //===----------------------------------------------------------------------===// // Type reconstruction //===----------------------------------------------------------------------===// @@ -8010,6 +8094,13 @@ QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E, } template<typename Derived> +QualType TreeTransform<Derived>::RebuildUnaryTransformType(QualType BaseType, + UnaryTransformType::UTTKind UKind, + SourceLocation Loc) { + return SemaRef.BuildUnaryTransformType(BaseType, UKind, Loc); +} + +template<typename Derived> QualType TreeTransform<Derived>::RebuildTemplateSpecializationType( TemplateName Template, SourceLocation TemplateNameLoc, |