From a3fa5c7f1b5e2ba4d6ec033dc0e2376326b05824 Mon Sep 17 00:00:00 2001 From: rdivacky Date: Fri, 15 Jan 2010 15:39:40 +0000 Subject: Update clang to r93512. --- lib/Sema/CMakeLists.txt | 1 + lib/Sema/CodeCompleteConsumer.cpp | 51 +- lib/Sema/IdentifierResolver.cpp | 42 - lib/Sema/IdentifierResolver.h | 11 - lib/Sema/Lookup.h | 31 +- lib/Sema/Sema.cpp | 322 +------ lib/Sema/Sema.h | 116 ++- lib/Sema/SemaCXXCast.cpp | 2 +- lib/Sema/SemaCXXScopeSpec.cpp | 26 + lib/Sema/SemaChecking.cpp | 478 +++++++++- lib/Sema/SemaCodeComplete.cpp | 1598 ++++++++++++++++++++++------------ lib/Sema/SemaDecl.cpp | 319 ++++++- lib/Sema/SemaDeclAttr.cpp | 21 +- lib/Sema/SemaDeclCXX.cpp | 244 ++++-- lib/Sema/SemaDeclObjC.cpp | 110 ++- lib/Sema/SemaExpr.cpp | 340 +++++--- lib/Sema/SemaExprCXX.cpp | 279 +----- lib/Sema/SemaExprObjC.cpp | 5 +- lib/Sema/SemaInit.cpp | 62 +- lib/Sema/SemaLookup.cpp | 295 +++++-- lib/Sema/SemaOverload.cpp | 816 +++++++++++------ lib/Sema/SemaOverload.h | 184 +++- lib/Sema/SemaStmt.cpp | 9 +- lib/Sema/SemaTemplate.cpp | 54 +- lib/Sema/SemaTemplateDeduction.cpp | 29 +- lib/Sema/SemaTemplateInstantiate.cpp | 7 + lib/Sema/SemaType.cpp | 63 +- lib/Sema/TargetAttributesSema.cpp | 86 ++ lib/Sema/TargetAttributesSema.h | 27 + lib/Sema/TreeTransform.h | 64 +- 30 files changed, 3811 insertions(+), 1881 deletions(-) create mode 100644 lib/Sema/TargetAttributesSema.cpp create mode 100644 lib/Sema/TargetAttributesSema.h (limited to 'lib/Sema') diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index fd3265d..5be6712 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -29,6 +29,7 @@ add_clang_library(clangSema SemaTemplateInstantiate.cpp SemaTemplateInstantiateDecl.cpp SemaType.cpp + TargetAttributesSema.cpp ) add_dependencies(clangSema ClangDiagnosticSema) diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index b9b85df..fbd1450 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -85,6 +85,26 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) case CK_Comma: this->Text = ", "; break; + + case CK_Colon: + this->Text = ": "; + break; + + case CK_SemiColon: + this->Text = ";"; + break; + + case CK_Equal: + this->Text = " = "; + break; + + case CK_HorizontalSpace: + this->Text = " "; + break; + + case CK_VerticalSpace: + this->Text = "\n"; + break; } } @@ -140,6 +160,11 @@ CodeCompletionString::Chunk CodeCompletionString::Chunk::Clone() const { case CK_LeftAngle: case CK_RightAngle: case CK_Comma: + case CK_Colon: + case CK_SemiColon: + case CK_Equal: + case CK_HorizontalSpace: + case CK_VerticalSpace: return Chunk(Kind, Text); case CK_Optional: { @@ -177,6 +202,11 @@ CodeCompletionString::Chunk::Destroy() { case CK_LeftAngle: case CK_RightAngle: case CK_Comma: + case CK_Colon: + case CK_SemiColon: + case CK_Equal: + case CK_HorizontalSpace: + case CK_VerticalSpace: break; } } @@ -271,6 +301,11 @@ void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const { case CK_LeftAngle: case CK_RightAngle: case CK_Comma: + case CK_Colon: + case CK_SemiColon: + case CK_Equal: + case CK_HorizontalSpace: + case CK_VerticalSpace: break; } } @@ -326,6 +361,11 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str, case CK_LeftAngle: case CK_RightAngle: case CK_Comma: + case CK_Colon: + case CK_SemiColon: + case CK_Equal: + case CK_HorizontalSpace: + case CK_VerticalSpace: Result->AddChunk(Chunk(Kind)); break; } @@ -386,8 +426,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, OS << "COMPLETION: "; switch (Results[I].Kind) { case Result::RK_Declaration: - OS << Results[I].Declaration->getNameAsString() << " : " - << Results[I].Rank; + OS << Results[I].Declaration->getNameAsString() ; if (Results[I].Hidden) OS << " (Hidden)"; if (CodeCompletionString *CCS @@ -400,13 +439,13 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, break; case Result::RK_Keyword: - OS << Results[I].Keyword << " : " << Results[I].Rank << '\n'; + OS << Results[I].Keyword << '\n'; break; case Result::RK_Macro: { - OS << Results[I].Macro->getName() << " : " << Results[I].Rank; + OS << Results[I].Macro->getName(); if (CodeCompletionString *CCS - = Results[I].CreateCodeCompletionString(SemaRef)) { + = Results[I].CreateCodeCompletionString(SemaRef)) { OS << " : " << CCS->getAsString(); delete CCS; } @@ -415,7 +454,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, } case Result::RK_Pattern: { - OS << "Pattern : " << Results[I].Rank << " : " + OS << "Pattern : " << Results[I].Pattern->getAsString() << '\n'; break; } diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp index 0dbf219..bff4751 100644 --- a/lib/Sema/IdentifierResolver.cpp +++ b/lib/Sema/IdentifierResolver.cpp @@ -46,22 +46,6 @@ public: // IdDeclInfo Implementation //===----------------------------------------------------------------------===// -/// AddShadowed - Add a decl by putting it directly above the 'Shadow' decl. -/// Later lookups will find the 'Shadow' decl first. The 'Shadow' decl must -/// be already added to the scope chain and must be in the same context as -/// the decl that we want to add. -void IdentifierResolver::IdDeclInfo::AddShadowed(NamedDecl *D, - NamedDecl *Shadow) { - for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) { - if (Shadow == *(I-1)) { - Decls.insert(I-1, D); - return; - } - } - - assert(0 && "Shadow wasn't in scope chain!"); -} - /// RemoveDecl - Remove the decl from the scope chain. /// The decl must already be part of the decl chain. void IdentifierResolver::IdDeclInfo::RemoveDecl(NamedDecl *D) { @@ -160,32 +144,6 @@ void IdentifierResolver::AddDecl(NamedDecl *D) { IDI->AddDecl(D); } -/// AddShadowedDecl - Link the decl to its shadowed decl chain putting it -/// after the decl that the iterator points to, thus the 'Shadow' decl will be -/// encountered before the 'D' decl. -void IdentifierResolver::AddShadowedDecl(NamedDecl *D, NamedDecl *Shadow) { - assert(D->getDeclName() == Shadow->getDeclName() && "Different ids!"); - - DeclarationName Name = D->getDeclName(); - void *Ptr = Name.getFETokenInfo(); - assert(Ptr && "No decl from Ptr ?"); - - IdDeclInfo *IDI; - - if (isDeclPtr(Ptr)) { - Name.setFETokenInfo(NULL); - IDI = &(*IdDeclInfos)[Name]; - NamedDecl *PrevD = static_cast(Ptr); - assert(PrevD == Shadow && "Invalid shadow decl ?"); - IDI->AddDecl(D); - IDI->AddDecl(PrevD); - return; - } - - IDI = toIdDeclInfo(Ptr); - IDI->AddShadowed(D, Shadow); -} - /// RemoveDecl - Unlink the decl from its shadowed decl chain. /// The decl must already be part of the decl chain. void IdentifierResolver::RemoveDecl(NamedDecl *D) { diff --git a/lib/Sema/IdentifierResolver.h b/lib/Sema/IdentifierResolver.h index 65f3256..59bd834 100644 --- a/lib/Sema/IdentifierResolver.h +++ b/lib/Sema/IdentifierResolver.h @@ -41,12 +41,6 @@ class IdentifierResolver { void AddDecl(NamedDecl *D) { Decls.push_back(D); } - /// AddShadowed - Add a decl by putting it directly above the 'Shadow' decl. - /// Later lookups will find the 'Shadow' decl first. The 'Shadow' decl must - /// be already added to the scope chain and must be in the same context as - /// the decl that we want to add. - void AddShadowed(NamedDecl *D, NamedDecl *Shadow); - /// RemoveDecl - Remove the decl from the scope chain. /// The decl must already be part of the decl chain. void RemoveDecl(NamedDecl *D); @@ -163,11 +157,6 @@ public: /// AddDecl - Link the decl to its shadowed decl chain. void AddDecl(NamedDecl *D); - /// AddShadowedDecl - Link the decl to its shadowed decl chain putting it - /// after the decl that the iterator points to, thus the 'Shadow' decl will be - /// encountered before the 'D' decl. - void AddShadowedDecl(NamedDecl *D, NamedDecl *Shadow); - /// RemoveDecl - Unlink the decl from its shadowed decl chain. /// The decl must already be part of the decl chain. void RemoveDecl(NamedDecl *D); diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index c5eecda..9064de6 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -32,6 +32,11 @@ public: /// @brief No entity found met the criteria. NotFound = 0, + /// @brief No entity found met the criteria within the current + /// instantiation,, but there were dependent base classes of the + /// current instantiation that could not be searched. + NotFoundInCurrentInstantiation, + /// @brief Name lookup found a single declaration that met the /// criteria. getFoundDecl() will return this declaration. Found, @@ -268,6 +273,19 @@ public: Decls.set_size(N); } + /// \brief Determine whether no result was found because we could not + /// search into dependent base classes of the current instantiation. + bool wasNotFoundInCurrentInstantiation() const { + return ResultKind == NotFoundInCurrentInstantiation; + } + + /// \brief Note that while no result was found in the current instantiation, + /// there were dependent base classes that could not be searched. + void setNotFoundInCurrentInstantiation() { + assert(ResultKind == NotFound && Decls.empty()); + ResultKind = NotFoundInCurrentInstantiation; + } + /// \brief Resolves the result kind of the lookup, possibly hiding /// decls. /// @@ -278,9 +296,10 @@ public: /// \brief Re-resolves the result kind of the lookup after a set of /// removals has been performed. void resolveKindAfterFilter() { - if (Decls.empty()) - ResultKind = NotFound; - else { + if (Decls.empty()) { + if (ResultKind != NotFoundInCurrentInstantiation) + ResultKind = NotFound; + } else { ResultKind = Found; resolveKind(); } @@ -524,7 +543,11 @@ private: /// /// \param Hiding a declaration that hides the declaration \p ND, /// or NULL if no such declaration exists. - virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding) = 0; + /// + /// \param InBaseClass whether this declaration was found in base + /// class of the context we searched. + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, + bool InBaseClass) = 0; }; } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 40ad90a..171101b 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "TargetAttributesSema.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/APFloat.h" #include "clang/AST/ASTConsumer.h" @@ -109,6 +110,12 @@ static bool ShouldAKA(ASTContext &Context, QualType QT, if (isa(Underlying)) break; + // Don't desugar through the primary typedef of an anonymous type. + if (isa(Underlying) && isa(QT)) + if (cast(Underlying)->getDecl()->getTypedefForAnonDecl() == + cast(QT)->getDecl()) + break; + // Otherwise, we're tearing through something opaque; note that // we'll eventually need an a.k.a. clause and keep going. AKA = true; @@ -347,7 +354,8 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, bool CompleteTranslationUnit, CodeCompleteConsumer *CodeCompleter) - : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), + : TheTargetAttributesSema(0), + LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), CurBlock(0), PackContext(0), ParsingDeclDepth(0), @@ -368,313 +376,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0)); } -/// Retrieves the width and signedness of the given integer type, -/// or returns false if it is not an integer type. -/// -/// \param T must be canonical -static bool getIntProperties(ASTContext &C, const Type *T, - unsigned &BitWidth, bool &Signed) { - assert(T->isCanonicalUnqualified()); - - if (const VectorType *VT = dyn_cast(T)) - T = VT->getElementType().getTypePtr(); - if (const ComplexType *CT = dyn_cast(T)) - T = CT->getElementType().getTypePtr(); - - if (const BuiltinType *BT = dyn_cast(T)) { - if (!BT->isInteger()) return false; - - BitWidth = C.getIntWidth(QualType(T, 0)); - Signed = BT->isSignedInteger(); - return true; - } - - return false; -} - -/// Checks whether the given value will have the same value if it it -/// is truncated to the given width, then extended back to the -/// original width. -static bool IsSameIntAfterCast(const llvm::APSInt &value, - unsigned TargetWidth) { - unsigned SourceWidth = value.getBitWidth(); - llvm::APSInt truncated = value; - truncated.trunc(TargetWidth); - truncated.extend(SourceWidth); - return (truncated == value); -} - -/// Checks whether the given value will have the same value if it -/// is truncated to the given width, then extended back to the original -/// width. -/// -/// The value might be a vector or a complex. -static bool IsSameIntAfterCast(const APValue &value, unsigned TargetWidth) { - if (value.isInt()) - return IsSameIntAfterCast(value.getInt(), TargetWidth); - - if (value.isVector()) { - for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i) - if (!IsSameIntAfterCast(value.getVectorElt(i), TargetWidth)) - return false; - return true; - } - - if (value.isComplexInt()) { - return IsSameIntAfterCast(value.getComplexIntReal(), TargetWidth) && - IsSameIntAfterCast(value.getComplexIntImag(), TargetWidth); - } - - // This can happen with lossless casts to intptr_t of "based" lvalues. - // Assume it might use arbitrary bits. - assert(value.isLValue()); - return false; -} - - -/// Checks whether the given value, which currently has the given -/// source semantics, has the same value when coerced through the -/// target semantics. -static bool IsSameFloatAfterCast(const llvm::APFloat &value, - const llvm::fltSemantics &Src, - const llvm::fltSemantics &Tgt) { - llvm::APFloat truncated = value; - - bool ignored; - truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored); - truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored); - - return truncated.bitwiseIsEqual(value); -} - -/// Checks whether the given value, which currently has the given -/// source semantics, has the same value when coerced through the -/// target semantics. -/// -/// The value might be a vector of floats (or a complex number). -static bool IsSameFloatAfterCast(const APValue &value, - const llvm::fltSemantics &Src, - const llvm::fltSemantics &Tgt) { - if (value.isFloat()) - return IsSameFloatAfterCast(value.getFloat(), Src, Tgt); - - if (value.isVector()) { - for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i) - if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt)) - return false; - return true; - } - - assert(value.isComplexFloat()); - return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) && - IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); -} - -/// Determines if it's reasonable for the given expression to be truncated -/// down to the given integer width. -/// * Boolean expressions are automatically white-listed. -/// * Arithmetic operations on implicitly-promoted operands of the -/// target width or less are okay --- not because the results are -/// actually guaranteed to fit within the width, but because the -/// user is effectively pretending that the operations are closed -/// within the implicitly-promoted type. -static bool IsExprValueWithinWidth(ASTContext &C, Expr *E, unsigned Width) { - E = E->IgnoreParens(); - -#ifndef NDEBUG - { - const Type *ETy = E->getType()->getCanonicalTypeInternal().getTypePtr(); - unsigned EWidth; - bool ESigned; - - if (!getIntProperties(C, ETy, EWidth, ESigned)) - assert(0 && "expression not of integer type"); - - // The caller should never let this happen. - assert(EWidth > Width && "called on expr whose type is too small"); - } -#endif - - // Strip implicit casts off. - while (isa(E)) { - E = cast(E)->getSubExpr(); - - const Type *ETy = E->getType()->getCanonicalTypeInternal().getTypePtr(); - - unsigned EWidth; - bool ESigned; - if (!getIntProperties(C, ETy, EWidth, ESigned)) - return false; - - if (EWidth <= Width) - return true; - } - - if (BinaryOperator *BO = dyn_cast(E)) { - switch (BO->getOpcode()) { - - // Boolean-valued operations are white-listed. - case BinaryOperator::LAnd: - case BinaryOperator::LOr: - case BinaryOperator::LT: - case BinaryOperator::GT: - case BinaryOperator::LE: - case BinaryOperator::GE: - case BinaryOperator::EQ: - case BinaryOperator::NE: - return true; - - // Operations with opaque sources are black-listed. - case BinaryOperator::PtrMemD: - case BinaryOperator::PtrMemI: - return false; - - // Left shift gets black-listed based on a judgement call. - case BinaryOperator::Shl: - return false; - - // Various special cases. - case BinaryOperator::Shr: - return IsExprValueWithinWidth(C, BO->getLHS(), Width); - case BinaryOperator::Comma: - return IsExprValueWithinWidth(C, BO->getRHS(), Width); - case BinaryOperator::Sub: - if (BO->getLHS()->getType()->isPointerType()) - return false; - // fallthrough - - // Any other operator is okay if the operands are - // promoted from expressions of appropriate size. - default: - return IsExprValueWithinWidth(C, BO->getLHS(), Width) && - IsExprValueWithinWidth(C, BO->getRHS(), Width); - } - } - - if (UnaryOperator *UO = dyn_cast(E)) { - switch (UO->getOpcode()) { - // Boolean-valued operations are white-listed. - case UnaryOperator::LNot: - return true; - - // Operations with opaque sources are black-listed. - case UnaryOperator::Deref: - case UnaryOperator::AddrOf: // should be impossible - return false; - - case UnaryOperator::OffsetOf: - return false; - - default: - return IsExprValueWithinWidth(C, UO->getSubExpr(), Width); - } - } - - // Don't diagnose if the expression is an integer constant - // whose value in the target type is the same as it was - // in the original type. - Expr::EvalResult result; - if (E->Evaluate(result, C)) - if (IsSameIntAfterCast(result.Val, Width)) - return true; - - return false; -} - -/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. -static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) { - S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange(); -} - -/// Implements -Wconversion. -static void CheckImplicitConversion(Sema &S, Expr *E, QualType T) { - // Don't diagnose in unevaluated contexts. - if (S.ExprEvalContexts.back().Context == Sema::Unevaluated) - return; - - // Don't diagnose for value-dependent expressions. - if (E->isValueDependent()) - return; - - const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr(); - const Type *Target = S.Context.getCanonicalType(T).getTypePtr(); - - // Never diagnose implicit casts to bool. - if (Target->isSpecificBuiltinType(BuiltinType::Bool)) - return; - - // Strip vector types. - if (isa(Source)) { - if (!isa(Target)) - return DiagnoseImpCast(S, E, T, diag::warn_impcast_vector_scalar); - - Source = cast(Source)->getElementType().getTypePtr(); - Target = cast(Target)->getElementType().getTypePtr(); - } - - // Strip complex types. - if (isa(Source)) { - if (!isa(Target)) - return DiagnoseImpCast(S, E, T, diag::warn_impcast_complex_scalar); - - Source = cast(Source)->getElementType().getTypePtr(); - Target = cast(Target)->getElementType().getTypePtr(); - } - - const BuiltinType *SourceBT = dyn_cast(Source); - const BuiltinType *TargetBT = dyn_cast(Target); - - // If the source is floating point... - if (SourceBT && SourceBT->isFloatingPoint()) { - // ...and the target is floating point... - if (TargetBT && TargetBT->isFloatingPoint()) { - // ...then warn if we're dropping FP rank. - - // Builtin FP kinds are ordered by increasing FP rank. - if (SourceBT->getKind() > TargetBT->getKind()) { - // Don't warn about float constants that are precisely - // representable in the target type. - Expr::EvalResult result; - if (E->Evaluate(result, S.Context)) { - // Value might be a float, a float vector, or a float complex. - if (IsSameFloatAfterCast(result.Val, - S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)), - S.Context.getFloatTypeSemantics(QualType(SourceBT, 0)))) - return; - } - - DiagnoseImpCast(S, E, T, diag::warn_impcast_float_precision); - } - return; - } - - // If the target is integral, always warn. - if ((TargetBT && TargetBT->isInteger())) - // TODO: don't warn for integer values? - return DiagnoseImpCast(S, E, T, diag::warn_impcast_float_integer); - - return; - } - - unsigned SourceWidth, TargetWidth; - bool SourceSigned, TargetSigned; - - if (!getIntProperties(S.Context, Source, SourceWidth, SourceSigned) || - !getIntProperties(S.Context, Target, TargetWidth, TargetSigned)) - return; - - if (SourceWidth > TargetWidth) { - if (IsExprValueWithinWidth(S.Context, E, TargetWidth)) - return; - - // People want to build with -Wshorten-64-to-32 and not -Wconversion - // and by god we'll let them. - if (SourceWidth == 64 && TargetWidth == 32) - return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_64_32); - return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_precision); - } - - return; +Sema::~Sema() { + if (PackContext) FreePackedContext(); + delete TheTargetAttributesSema; } /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. @@ -697,7 +401,7 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, } } - CheckImplicitConversion(*this, Expr, Ty); + CheckImplicitConversion(Expr, Ty); if (ImplicitCastExpr *ImpCast = dyn_cast(Expr)) { if (ImpCast->getCastKind() == Kind) { diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 4cecee4..fab7292 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -42,6 +42,7 @@ namespace llvm { } namespace clang { + class AnalysisContext; class ASTContext; class ASTConsumer; class CodeCompleteConsumer; @@ -101,6 +102,7 @@ namespace clang { class InitializationKind; class InitializationSequence; class VisibleDeclConsumer; + class TargetAttributesSema; /// BlockSemaInfo - When a block is being parsed, this contains information /// about the block. It is pointed to from Sema::CurBlock. @@ -176,6 +178,7 @@ public: class Sema : public Action { Sema(const Sema&); // DO NOT IMPLEMENT void operator=(const Sema&); // DO NOT IMPLEMENT + mutable const TargetAttributesSema* TheTargetAttributesSema; public: const LangOptions &LangOpts; Preprocessor &PP; @@ -426,13 +429,12 @@ public: Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, bool CompleteTranslationUnit = true, CodeCompleteConsumer *CompletionConsumer = 0); - ~Sema() { - if (PackContext) FreePackedContext(); - } + ~Sema(); const LangOptions &getLangOptions() const { return LangOpts; } Diagnostic &getDiagnostics() const { return Diags; } SourceManager &getSourceManager() const { return SourceMgr; } + const TargetAttributesSema &getTargetAttributesSema() const; /// \brief Helper class that creates diagnostics with optional /// template instantiation stacks. @@ -561,8 +563,6 @@ public: const FunctionProtoType *Target, SourceLocation TargetLoc, const FunctionProtoType *Source, SourceLocation SourceLoc); - QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D); - bool UnwrapSimilarPointerTypes(QualType& T1, QualType& T2); virtual TypeResult ActOnTypeName(Scope *S, Declarator &D); @@ -1030,10 +1030,25 @@ public: OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet, SourceLocation Loc, OverloadCandidateSet::iterator& Best); + + enum OverloadCandidateDisplayKind { + /// Requests that all candidates be shown. Viable candidates will + /// be printed first. + OCD_AllCandidates, + + /// Requests that only viable candidates be shown. + OCD_ViableCandidates + }; void PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, - bool OnlyViable, - const char *Opc=0, - SourceLocation Loc=SourceLocation()); + OverloadCandidateDisplayKind OCD, + Expr **Args, unsigned NumArgs, + const char *Opc = 0, + SourceLocation Loc = SourceLocation()); + + void NoteOverloadCandidate(FunctionDecl *Fn); + void DiagnoseAmbiguousConversion(const ImplicitConversionSequence &ICS, + SourceLocation CaretLoc, + const PartialDiagnostic &PDiag); FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, bool Complain); @@ -1083,6 +1098,9 @@ public: OwningExprResult BuildOverloadedArrowExpr(Scope *S, ExprArg Base, SourceLocation OpLoc); + /// CheckUnreachable - Check for unreachable code. + void CheckUnreachable(AnalysisContext &); + /// CheckCallReturnType - Checks that a call expression's return type is /// complete. Returns true on failure. The location passed in is the location /// that best represents the call. @@ -1090,14 +1108,14 @@ public: CallExpr *CE, FunctionDecl *FD); /// Helpers for dealing with blocks and functions. - void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body); - void CheckFallThroughForBlock(QualType BlockTy, Stmt *Body); + void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, AnalysisContext &); + void CheckFallThroughForBlock(QualType BlockTy, Stmt *, AnalysisContext &); bool CheckParmsForFunctionDef(FunctionDecl *FD); void CheckCXXDefaultArguments(FunctionDecl *FD); void CheckExtraCXXDefaultArguments(Declarator &D); enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1, AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 }; - ControlFlowKind CheckFallThrough(Stmt *); + ControlFlowKind CheckFallThrough(AnalysisContext &); Scope *getNonFieldDeclScope(Scope *S); @@ -1168,8 +1186,14 @@ public: LookupObjCImplementationName }; + /// \brief Specifies whether (or how) name lookup is being performed for a + /// redeclaration (vs. a reference). enum RedeclarationKind { - NotForRedeclaration, + /// \brief The lookup is a reference to this name that is not for the + /// purpose of redeclaring the name. + NotForRedeclaration = 0, + /// \brief The lookup results will be used for redeclaration of a name, + /// if an entity by that name already exists. ForRedeclaration }; @@ -1188,7 +1212,8 @@ public: = NotForRedeclaration); bool LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation = false); - bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx); + bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, + bool InUnqualifiedLookup = false); bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS, bool AllowBuiltinCreation = false, bool EnteringContext = false); @@ -1210,7 +1235,8 @@ public: bool CorrectTypo(LookupResult &R, Scope *S, const CXXScopeSpec *SS, DeclContext *MemberContext = 0, - bool EnteringContext = false); + bool EnteringContext = false, + const ObjCObjectPointerType *OPT = 0); void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, AssociatedNamespaceSet &AssociatedNamespaces, @@ -1219,7 +1245,8 @@ public: bool DiagnoseAmbiguousLookup(LookupResult &Result); //@} - ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id); + ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id, + SourceLocation RecoverLoc = SourceLocation()); NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S, bool ForRedeclaration, SourceLocation Loc); @@ -1383,7 +1410,8 @@ public: MultiExprArg Exprs, ExprArg AsmString, MultiExprArg Clobbers, - SourceLocation RParenLoc); + SourceLocation RParenLoc, + bool MSAsm = false); virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, @@ -1437,10 +1465,6 @@ public: void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, Expr **Args, unsigned NumArgs); - void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc, - const PartialDiagnostic &PD, - bool Equality = false); - virtual void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext); @@ -1462,7 +1486,8 @@ public: OwningExprResult LookupInObjCMethod(LookupResult &R, Scope *S, - IdentifierInfo *II); + IdentifierInfo *II, + bool AllowBuiltinCreation=false); OwningExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS, DeclarationName Name, @@ -1571,13 +1596,13 @@ public: QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs); OwningExprResult LookupMemberExpr(LookupResult &R, Expr *&Base, bool &IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, - NamedDecl *FirstQualifierInScope, DeclPtrTy ObjCImpDecl); bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, @@ -2008,6 +2033,7 @@ public: bool isDependentScopeSpecifier(const CXXScopeSpec &SS); CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); bool isUnknownSpecialization(const CXXScopeSpec &SS); + bool isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS); /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the /// global scope ('::'). @@ -2175,11 +2201,11 @@ public: void MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor); /// ClassesWithUnmarkedVirtualMembers - Contains record decls whose virtual - /// members might need to be marked as referenced. This is either done when - /// the key function definition is emitted (this is handled by by - /// MaybeMarkVirtualMembersReferenced), or at the end of the translation unit - /// (done by ProcessPendingClassesWithUnmarkedVirtualMembers). - std::map ClassesWithUnmarkedVirtualMembers; + /// members need to be marked as referenced at the end of the translation + /// unit. It will contain polymorphic classes that do not have a key + /// function or have a key function that has been defined. + llvm::SmallVector, 4> + ClassesWithUnmarkedVirtualMembers; /// MaybeMarkVirtualMembersReferenced - If the passed in method is the /// key function of the record decl, will mark virtual member functions as @@ -2236,8 +2262,6 @@ public: void CheckConversionDeclarator(Declarator &D, QualType &R, FunctionDecl::StorageClass& SC); DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion); - - bool isImplicitMemberReference(const LookupResult &R, QualType &ThisType); //===--------------------------------------------------------------------===// // C++ Derived Classes @@ -2338,6 +2362,8 @@ public: bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl); + bool CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl); + //===--------------------------------------------------------------------===// // C++ Templates [C++ 14] // @@ -2350,6 +2376,14 @@ public: TypeTy *ObjectType, bool EnteringContext, TemplateTy &Template); + + virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, + SourceLocation IILoc, + Scope *S, + const CXXScopeSpec *SS, + TemplateTy &SuggestedTemplate, + TemplateNameKind &SuggestedKind); + bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); TemplateDecl *AdjustDeclIfTemplate(DeclPtrTy &Decl); @@ -3348,10 +3382,11 @@ public: void MergeOneProtocolPropertiesIntoClass(Decl *CDecl, ObjCProtocolDecl *PDecl); - virtual void ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, - DeclPtrTy *allMethods = 0, unsigned allNum = 0, - DeclPtrTy *allProperties = 0, unsigned pNum = 0, - DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0); + virtual void ActOnAtEnd(SourceRange AtEnd, + DeclPtrTy classDecl, + DeclPtrTy *allMethods = 0, unsigned allNum = 0, + DeclPtrTy *allProperties = 0, unsigned pNum = 0, + DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0); virtual DeclPtrTy ActOnProperty(Scope *S, SourceLocation AtLoc, FieldDeclarator &FD, ObjCDeclSpec &ODS, @@ -3617,9 +3652,6 @@ public: bool PerformImplicitConversion(Expr *&From, QualType ToType, const StandardConversionSequence& SCS, AssignmentAction Action, bool IgnoreBaseAccess); - - bool BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind, - const ImplicitConversionSequence& ICS); /// the following "Check" methods will return a valid/converted QualType /// or a null QualType (indicating an error diagnostic was issued). @@ -3629,7 +3661,8 @@ public: QualType CheckPointerToMemberOperands( // C++ 5.5 Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isIndirect); QualType CheckMultiplyDivideOperands( // C99 6.5.5 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign, + bool isDivide); QualType CheckRemainderOperands( // C99 6.5.5 Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); QualType CheckAdditionOperands( // C99 6.5.6 @@ -3801,7 +3834,8 @@ public: /// \name Code completion //@{ - virtual void CodeCompleteOrdinaryName(Scope *S); + virtual void CodeCompleteOrdinaryName(Scope *S, + CodeCompletionContext CompletionContext); virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base, SourceLocation OpLoc, bool IsArrow); @@ -3819,6 +3853,7 @@ public: virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, bool InInterface); + virtual void CodeCompleteObjCAtVisibility(Scope *S); virtual void CodeCompleteObjCAtStatement(Scope *S); virtual void CodeCompleteObjCAtExpression(Scope *S); virtual void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS); @@ -3895,6 +3930,11 @@ private: void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc); void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex); + void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc, + const PartialDiagnostic &PD, + bool Equality = false); + void CheckImplicitConversion(Expr *E, QualType Target); + }; //===--------------------------------------------------------------------===// diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 800c544..f924bd3 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -893,7 +893,7 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, /*InOverloadResolution=*/false, /*one of user provided casts*/true); - if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) + if (ICS.isBad()) return TC_NotApplicable; // The conversion is possible, so commit to it. diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 82d58ea..8594583 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -210,6 +210,28 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) { return getCurrentInstantiationOf(NNS) == 0; } +/// \brief Determine whether the given scope specifier refers to a +/// current instantiation that has any dependent base clases. +/// +/// This check is typically used when we've performed lookup into the +/// current instantiation of a template, but that lookup failed. When +/// there are dependent bases present, however, the lookup needs to be +/// delayed until template instantiation time. +bool Sema::isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS) { + if (!SS.isSet()) + return false; + + NestedNameSpecifier *NNS = (NestedNameSpecifier*)SS.getScopeRep(); + if (!NNS->isDependent()) + return false; + + CXXRecordDecl *CurrentInstantiation = getCurrentInstantiationOf(NNS); + if (!CurrentInstantiation) + return false; + + return CurrentInstantiation->hasAnyDependentBases(); +} + /// \brief If the given nested name specifier refers to the current /// instantiation, return the declaration that corresponds to that /// current instantiation (C++0x [temp.dep.type]p1). @@ -446,6 +468,10 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, << Name << Found.getLookupName() << CodeModificationHint::CreateReplacement(Found.getNameLoc(), Found.getLookupName().getAsString()); + + if (NamedDecl *ND = Found.getAsSingle()) + Diag(ND->getLocation(), diag::note_previous_decl) + << ND->getDeclName(); } else Found.clear(); } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index f10fa07..5f124e4 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -14,6 +14,7 @@ #include "Sema.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" @@ -318,7 +319,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { // Determine the index of the size. unsigned SizeIndex; - switch (Context.getTypeSize(ValType)/8) { + switch (Context.getTypeSizeInChars(ValType).getQuantity()) { case 1: SizeIndex = 0; break; case 2: SizeIndex = 1; break; case 4: SizeIndex = 2; break; @@ -966,9 +967,6 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull, /// /// (8) Check that the format string is a wide literal. /// -/// (9) Also check the arguments of functions with the __format__ attribute. -/// (TODO). -/// /// All of these checks can be done by parsing the format string. /// /// For now, we ONLY do (1), (3), (5), (6), (7), and (8). @@ -1559,3 +1557,475 @@ void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) { Diag(loc, diag::warn_floatingpoint_eq) << lex->getSourceRange() << rex->getSourceRange(); } + +//===--- CHECK: Integer mixed-sign comparisons (-Wsign-compare) --------===// +//===--- CHECK: Lossy implicit conversions (-Wconversion) --------------===// + +namespace { + +/// Structure recording the 'active' range of an integer-valued +/// expression. +struct IntRange { + /// The number of bits active in the int. + unsigned Width; + + /// True if the int is known not to have negative values. + bool NonNegative; + + IntRange() {} + IntRange(unsigned Width, bool NonNegative) + : Width(Width), NonNegative(NonNegative) + {} + + // Returns the range of the bool type. + static IntRange forBoolType() { + return IntRange(1, true); + } + + // Returns the range of an integral type. + static IntRange forType(ASTContext &C, QualType T) { + return forCanonicalType(C, T->getCanonicalTypeInternal().getTypePtr()); + } + + // Returns the range of an integeral type based on its canonical + // representation. + static IntRange forCanonicalType(ASTContext &C, const Type *T) { + assert(T->isCanonicalUnqualified()); + + if (const VectorType *VT = dyn_cast(T)) + T = VT->getElementType().getTypePtr(); + if (const ComplexType *CT = dyn_cast(T)) + T = CT->getElementType().getTypePtr(); + if (const EnumType *ET = dyn_cast(T)) + T = ET->getDecl()->getIntegerType().getTypePtr(); + + const BuiltinType *BT = cast(T); + assert(BT->isInteger()); + + return IntRange(C.getIntWidth(QualType(T, 0)), BT->isUnsignedInteger()); + } + + // Returns the supremum of two ranges: i.e. their conservative merge. + static IntRange join(const IntRange &L, const IntRange &R) { + return IntRange(std::max(L.Width, R.Width), + L.NonNegative && R.NonNegative); + } + + // Returns the infinum of two ranges: i.e. their aggressive merge. + static IntRange meet(const IntRange &L, const IntRange &R) { + return IntRange(std::min(L.Width, R.Width), + L.NonNegative || R.NonNegative); + } +}; + +IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) { + if (value.isSigned() && value.isNegative()) + return IntRange(value.getMinSignedBits(), false); + + if (value.getBitWidth() > MaxWidth) + value.trunc(MaxWidth); + + // isNonNegative() just checks the sign bit without considering + // signedness. + return IntRange(value.getActiveBits(), true); +} + +IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, + unsigned MaxWidth) { + if (result.isInt()) + return GetValueRange(C, result.getInt(), MaxWidth); + + if (result.isVector()) { + IntRange R = GetValueRange(C, result.getVectorElt(0), Ty, MaxWidth); + for (unsigned i = 1, e = result.getVectorLength(); i != e; ++i) { + IntRange El = GetValueRange(C, result.getVectorElt(i), Ty, MaxWidth); + R = IntRange::join(R, El); + } + return R; + } + + if (result.isComplexInt()) { + IntRange R = GetValueRange(C, result.getComplexIntReal(), MaxWidth); + IntRange I = GetValueRange(C, result.getComplexIntImag(), MaxWidth); + return IntRange::join(R, I); + } + + // This can happen with lossless casts to intptr_t of "based" lvalues. + // Assume it might use arbitrary bits. + // FIXME: The only reason we need to pass the type in here is to get + // the sign right on this one case. It would be nice if APValue + // preserved this. + assert(result.isLValue()); + return IntRange(MaxWidth, Ty->isUnsignedIntegerType()); +} + +/// Pseudo-evaluate the given integer expression, estimating the +/// range of values it might take. +/// +/// \param MaxWidth - the width to which the value will be truncated +IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { + E = E->IgnoreParens(); + + // Try a full evaluation first. + Expr::EvalResult result; + if (E->Evaluate(result, C)) + return GetValueRange(C, result.Val, E->getType(), MaxWidth); + + // I think we only want to look through implicit casts here; if the + // user has an explicit widening cast, we should treat the value as + // being of the new, wider type. + if (ImplicitCastExpr *CE = dyn_cast(E)) { + if (CE->getCastKind() == CastExpr::CK_NoOp) + return GetExprRange(C, CE->getSubExpr(), MaxWidth); + + IntRange OutputTypeRange = IntRange::forType(C, CE->getType()); + + bool isIntegerCast = (CE->getCastKind() == CastExpr::CK_IntegralCast); + if (!isIntegerCast && CE->getCastKind() == CastExpr::CK_Unknown) + isIntegerCast = CE->getSubExpr()->getType()->isIntegerType(); + + // Assume that non-integer casts can span the full range of the type. + if (!isIntegerCast) + return OutputTypeRange; + + IntRange SubRange + = GetExprRange(C, CE->getSubExpr(), + std::min(MaxWidth, OutputTypeRange.Width)); + + // Bail out if the subexpr's range is as wide as the cast type. + if (SubRange.Width >= OutputTypeRange.Width) + return OutputTypeRange; + + // Otherwise, we take the smaller width, and we're non-negative if + // either the output type or the subexpr is. + return IntRange(SubRange.Width, + SubRange.NonNegative || OutputTypeRange.NonNegative); + } + + if (ConditionalOperator *CO = dyn_cast(E)) { + // If we can fold the condition, just take that operand. + bool CondResult; + if (CO->getCond()->EvaluateAsBooleanCondition(CondResult, C)) + return GetExprRange(C, CondResult ? CO->getTrueExpr() + : CO->getFalseExpr(), + MaxWidth); + + // Otherwise, conservatively merge. + IntRange L = GetExprRange(C, CO->getTrueExpr(), MaxWidth); + IntRange R = GetExprRange(C, CO->getFalseExpr(), MaxWidth); + return IntRange::join(L, R); + } + + if (BinaryOperator *BO = dyn_cast(E)) { + switch (BO->getOpcode()) { + + // Boolean-valued operations are single-bit and positive. + case BinaryOperator::LAnd: + case BinaryOperator::LOr: + case BinaryOperator::LT: + case BinaryOperator::GT: + case BinaryOperator::LE: + case BinaryOperator::GE: + case BinaryOperator::EQ: + case BinaryOperator::NE: + return IntRange::forBoolType(); + + // Operations with opaque sources are black-listed. + case BinaryOperator::PtrMemD: + case BinaryOperator::PtrMemI: + return IntRange::forType(C, E->getType()); + + // Bitwise-and uses the *infinum* of the two source ranges. + case BinaryOperator::And: + return IntRange::meet(GetExprRange(C, BO->getLHS(), MaxWidth), + GetExprRange(C, BO->getRHS(), MaxWidth)); + + // Left shift gets black-listed based on a judgement call. + case BinaryOperator::Shl: + return IntRange::forType(C, E->getType()); + + // Right shift by a constant can narrow its left argument. + case BinaryOperator::Shr: { + IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth); + + // If the shift amount is a positive constant, drop the width by + // that much. + llvm::APSInt shift; + if (BO->getRHS()->isIntegerConstantExpr(shift, C) && + shift.isNonNegative()) { + unsigned zext = shift.getZExtValue(); + if (zext >= L.Width) + L.Width = (L.NonNegative ? 0 : 1); + else + L.Width -= zext; + } + + return L; + } + + // Comma acts as its right operand. + case BinaryOperator::Comma: + return GetExprRange(C, BO->getRHS(), MaxWidth); + + // Black-list pointer subtractions. + case BinaryOperator::Sub: + if (BO->getLHS()->getType()->isPointerType()) + return IntRange::forType(C, E->getType()); + // fallthrough + + default: + break; + } + + // Treat every other operator as if it were closed on the + // narrowest type that encompasses both operands. + IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth); + IntRange R = GetExprRange(C, BO->getRHS(), MaxWidth); + return IntRange::join(L, R); + } + + if (UnaryOperator *UO = dyn_cast(E)) { + switch (UO->getOpcode()) { + // Boolean-valued operations are white-listed. + case UnaryOperator::LNot: + return IntRange::forBoolType(); + + // Operations with opaque sources are black-listed. + case UnaryOperator::Deref: + case UnaryOperator::AddrOf: // should be impossible + case UnaryOperator::OffsetOf: + return IntRange::forType(C, E->getType()); + + default: + return GetExprRange(C, UO->getSubExpr(), MaxWidth); + } + } + + FieldDecl *BitField = E->getBitField(); + if (BitField) { + llvm::APSInt BitWidthAP = BitField->getBitWidth()->EvaluateAsInt(C); + unsigned BitWidth = BitWidthAP.getZExtValue(); + + return IntRange(BitWidth, BitField->getType()->isUnsignedIntegerType()); + } + + return IntRange::forType(C, E->getType()); +} + +/// Checks whether the given value, which currently has the given +/// source semantics, has the same value when coerced through the +/// target semantics. +bool IsSameFloatAfterCast(const llvm::APFloat &value, + const llvm::fltSemantics &Src, + const llvm::fltSemantics &Tgt) { + llvm::APFloat truncated = value; + + bool ignored; + truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored); + truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored); + + return truncated.bitwiseIsEqual(value); +} + +/// Checks whether the given value, which currently has the given +/// source semantics, has the same value when coerced through the +/// target semantics. +/// +/// The value might be a vector of floats (or a complex number). +bool IsSameFloatAfterCast(const APValue &value, + const llvm::fltSemantics &Src, + const llvm::fltSemantics &Tgt) { + if (value.isFloat()) + return IsSameFloatAfterCast(value.getFloat(), Src, Tgt); + + if (value.isVector()) { + for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i) + if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt)) + return false; + return true; + } + + assert(value.isComplexFloat()); + return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) && + IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); +} + +} // end anonymous namespace + +/// \brief Implements -Wsign-compare. +/// +/// \param lex the left-hand expression +/// \param rex the right-hand expression +/// \param OpLoc the location of the joining operator +/// \param Equality whether this is an "equality-like" join, which +/// suppresses the warning in some cases +void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, + const PartialDiagnostic &PD, bool Equality) { + // Don't warn if we're in an unevaluated context. + if (ExprEvalContexts.back().Context == Unevaluated) + return; + + // If either expression is value-dependent, don't warn. We'll get another + // chance at instantiation time. + if (lex->isValueDependent() || rex->isValueDependent()) + return; + + QualType lt = lex->getType(), rt = rex->getType(); + + // Only warn if both operands are integral. + if (!lt->isIntegerType() || !rt->isIntegerType()) + return; + + // In C, the width of a bitfield determines its type, and the + // declared type only contributes the signedness. This duplicates + // the work that will later be done by UsualUnaryConversions. + // Eventually, this check will be reorganized in a way that avoids + // this duplication. + if (!getLangOptions().CPlusPlus) { + QualType tmp; + tmp = Context.isPromotableBitField(lex); + if (!tmp.isNull()) lt = tmp; + tmp = Context.isPromotableBitField(rex); + if (!tmp.isNull()) rt = tmp; + } + + // The rule is that the signed operand becomes unsigned, so isolate the + // signed operand. + Expr *signedOperand = lex, *unsignedOperand = rex; + QualType signedType = lt, unsignedType = rt; + if (lt->isSignedIntegerType()) { + if (rt->isSignedIntegerType()) return; + } else { + if (!rt->isSignedIntegerType()) return; + std::swap(signedOperand, unsignedOperand); + std::swap(signedType, unsignedType); + } + + unsigned unsignedWidth = Context.getIntWidth(unsignedType); + unsigned signedWidth = Context.getIntWidth(signedType); + + // If the unsigned type is strictly smaller than the signed type, + // then (1) the result type will be signed and (2) the unsigned + // value will fit fully within the signed type, and thus the result + // of the comparison will be exact. + if (signedWidth > unsignedWidth) + return; + + // Otherwise, calculate the effective ranges. + IntRange signedRange = GetExprRange(Context, signedOperand, signedWidth); + IntRange unsignedRange = GetExprRange(Context, unsignedOperand, unsignedWidth); + + // We should never be unable to prove that the unsigned operand is + // non-negative. + assert(unsignedRange.NonNegative && "unsigned range includes negative?"); + + // If the signed operand is non-negative, then the signed->unsigned + // conversion won't change it. + if (signedRange.NonNegative) + return; + + // For (in)equality comparisons, if the unsigned operand is a + // constant which cannot collide with a overflowed signed operand, + // then reinterpreting the signed operand as unsigned will not + // change the result of the comparison. + if (Equality && unsignedRange.Width < unsignedWidth) + return; + + Diag(OpLoc, PD) + << lt << rt << lex->getSourceRange() << rex->getSourceRange(); +} + +/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. +static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) { + S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange(); +} + +/// Implements -Wconversion. +void Sema::CheckImplicitConversion(Expr *E, QualType T) { + // Don't diagnose in unevaluated contexts. + if (ExprEvalContexts.back().Context == Sema::Unevaluated) + return; + + // Don't diagnose for value-dependent expressions. + if (E->isValueDependent()) + return; + + const Type *Source = Context.getCanonicalType(E->getType()).getTypePtr(); + const Type *Target = Context.getCanonicalType(T).getTypePtr(); + + // Never diagnose implicit casts to bool. + if (Target->isSpecificBuiltinType(BuiltinType::Bool)) + return; + + // Strip vector types. + if (isa(Source)) { + if (!isa(Target)) + return DiagnoseImpCast(*this, E, T, diag::warn_impcast_vector_scalar); + + Source = cast(Source)->getElementType().getTypePtr(); + Target = cast(Target)->getElementType().getTypePtr(); + } + + // Strip complex types. + if (isa(Source)) { + if (!isa(Target)) + return DiagnoseImpCast(*this, E, T, diag::warn_impcast_complex_scalar); + + Source = cast(Source)->getElementType().getTypePtr(); + Target = cast(Target)->getElementType().getTypePtr(); + } + + const BuiltinType *SourceBT = dyn_cast(Source); + const BuiltinType *TargetBT = dyn_cast(Target); + + // If the source is floating point... + if (SourceBT && SourceBT->isFloatingPoint()) { + // ...and the target is floating point... + if (TargetBT && TargetBT->isFloatingPoint()) { + // ...then warn if we're dropping FP rank. + + // Builtin FP kinds are ordered by increasing FP rank. + if (SourceBT->getKind() > TargetBT->getKind()) { + // Don't warn about float constants that are precisely + // representable in the target type. + Expr::EvalResult result; + if (E->Evaluate(result, Context)) { + // Value might be a float, a float vector, or a float complex. + if (IsSameFloatAfterCast(result.Val, + Context.getFloatTypeSemantics(QualType(TargetBT, 0)), + Context.getFloatTypeSemantics(QualType(SourceBT, 0)))) + return; + } + + DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_precision); + } + return; + } + + // If the target is integral, always warn. + if ((TargetBT && TargetBT->isInteger())) + // TODO: don't warn for integer values? + return DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_integer); + + return; + } + + if (!Source->isIntegerType() || !Target->isIntegerType()) + return; + + IntRange SourceRange = GetExprRange(Context, E, Context.getIntWidth(E->getType())); + IntRange TargetRange = IntRange::forCanonicalType(Context, Target); + + // FIXME: also signed<->unsigned? + + if (SourceRange.Width > TargetRange.Width) { + // People want to build with -Wshorten-64-to-32 and not -Wconversion + // and by god we'll let them. + if (SourceRange.Width == 64 && TargetRange.Width == 32) + return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_64_32); + return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_precision); + } + + return; +} + diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index ef82a94..a4cda01 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" @@ -111,14 +112,18 @@ namespace { /// \brief If non-NULL, a filter function used to remove any code-completion /// results that are not desirable. LookupFilter Filter; - + + /// \brief Whether we should allow declarations as + /// nested-name-specifiers that would otherwise be filtered out. + bool AllowNestedNameSpecifiers; + /// \brief A list of shadow maps, which is used to model name hiding at /// different levels of, e.g., the inheritance hierarchy. std::list ShadowMaps; public: explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0) - : SemaRef(SemaRef), Filter(Filter) { } + : SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false) { } /// \brief Set the filter used for code-completion results. void setFilter(LookupFilter Filter) { @@ -133,15 +138,55 @@ namespace { unsigned size() const { return Results.size(); } bool empty() const { return Results.empty(); } + /// \brief Specify whether nested-name-specifiers are allowed. + void allowNestedNameSpecifiers(bool Allow = true) { + AllowNestedNameSpecifiers = Allow; + } + + /// \brief Determine whether the given declaration is at all interesting + /// as a code-completion result. + /// + /// \param ND the declaration that we are inspecting. + /// + /// \param AsNestedNameSpecifier will be set true if this declaration is + /// only interesting when it is a nested-name-specifier. + bool isInterestingDecl(NamedDecl *ND, bool &AsNestedNameSpecifier) const; + + /// \brief Check whether the result is hidden by the Hiding declaration. + /// + /// \returns true if the result is hidden and cannot be found, false if + /// the hidden result could still be found. When false, \p R may be + /// modified to describe how the result can be found (e.g., via extra + /// qualification). + bool CheckHiddenResult(Result &R, DeclContext *CurContext, + NamedDecl *Hiding); + /// \brief Add a new result to this result set (if it isn't already in one /// of the shadow maps), or replace an existing result (for, e.g., a /// redeclaration). /// - /// \param R the result to add (if it is unique). + /// \param CurContext the result to add (if it is unique). /// /// \param R the context in which this result will be named. void MaybeAddResult(Result R, DeclContext *CurContext = 0); + /// \brief Add a new result to this result set, where we already know + /// the hiding declation (if any). + /// + /// \param R the result to add (if it is unique). + /// + /// \param CurContext the context in which this result will be named. + /// + /// \param Hiding the declaration that hides the result. + /// + /// \param InBaseClass whether the result was found in a base + /// class of the searched context. + void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding, + bool InBaseClass); + + /// \brief Add a new non-declaration result to this result set. + void AddResult(Result R); + /// \brief Enter into a new scope. void EnterNewScope(); @@ -158,6 +203,7 @@ namespace { /// //@{ bool IsOrdinaryName(NamedDecl *ND) const; + bool IsOrdinaryNonValueName(NamedDecl *ND) const; bool IsNestedNameSpecifier(NamedDecl *ND) const; bool IsEnum(NamedDecl *ND) const; bool IsClassOrStruct(NamedDecl *ND) const; @@ -166,6 +212,7 @@ namespace { bool IsNamespaceOrAlias(NamedDecl *ND) const; bool IsType(NamedDecl *ND) const; bool IsMember(NamedDecl *ND) const; + bool IsObjCIvar(NamedDecl *ND) const; //@} }; } @@ -259,31 +306,6 @@ ResultBuilder::ShadowMapEntry::end() const { return iterator(DeclOrVector.get()->end()); } -/// \brief Determines whether the given hidden result could be found with -/// some extra work, e.g., by qualifying the name. -/// -/// \param Hidden the declaration that is hidden by the currenly \p Visible -/// declaration. -/// -/// \param Visible the declaration with the same name that is already visible. -/// -/// \returns true if the hidden result can be found by some mechanism, -/// false otherwise. -static bool canHiddenResultBeFound(const LangOptions &LangOpts, - NamedDecl *Hidden, NamedDecl *Visible) { - // In C, there is no way to refer to a hidden name. - if (!LangOpts.CPlusPlus) - return false; - - DeclContext *HiddenCtx = Hidden->getDeclContext()->getLookupContext(); - - // There is no way to qualify a name declared in a function or method. - if (HiddenCtx->isFunctionOrMethod()) - return false; - - return HiddenCtx != Visible->getDeclContext()->getLookupContext(); -} - /// \brief Compute the qualification required to get from the current context /// (\p CurContext) to the target context (\p TargetContext). /// @@ -330,46 +352,37 @@ getRequiredQualification(ASTContext &Context, return Result; } -void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { - assert(!ShadowMaps.empty() && "Must enter into a results scope"); - - if (R.Kind != Result::RK_Declaration) { - // For non-declaration results, just add the result. - Results.push_back(R); - return; - } +bool ResultBuilder::isInterestingDecl(NamedDecl *ND, + bool &AsNestedNameSpecifier) const { + AsNestedNameSpecifier = false; + + ND = ND->getUnderlyingDecl(); + unsigned IDNS = ND->getIdentifierNamespace(); // Skip unnamed entities. - if (!R.Declaration->getDeclName()) - return; - - // Look through using declarations. - if (UsingShadowDecl *Using = dyn_cast(R.Declaration)) - MaybeAddResult(Result(Using->getTargetDecl(), R.Rank, R.Qualifier), - CurContext); - - Decl *CanonDecl = R.Declaration->getCanonicalDecl(); - unsigned IDNS = CanonDecl->getIdentifierNamespace(); + if (!ND->getDeclName()) + return false; // Friend declarations and declarations introduced due to friends are never // added as results. - if (isa(CanonDecl) || + if (isa(ND) || (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend))) - return; - + return false; + // Class template (partial) specializations are never added as results. - if (isa(CanonDecl) || - isa(CanonDecl)) - return; + if (isa(ND) || + isa(ND)) + return false; // Using declarations themselves are never added as results. - if (isa(CanonDecl)) - return; - - if (const IdentifierInfo *Id = R.Declaration->getIdentifier()) { + if (isa(ND)) + return false; + + // Some declarations have reserved names that we don't want to ever show. + if (const IdentifierInfo *Id = ND->getIdentifier()) { // __va_list_tag is a freak of nature. Find it and skip it. if (Id->isStr("__va_list_tag") || Id->isStr("__builtin_va_list")) - return; + return false; // Filter out names reserved for the implementation (C99 7.1.3, // C++ [lib.global.names]). Users don't need to see those. @@ -379,18 +392,83 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { const char *Name = Id->getNameStart(); if (Name[0] == '_' && (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z'))) - return; + return false; } } - + // C++ constructors are never found by name lookup. - if (isa(CanonDecl)) - return; + if (isa(ND)) + return false; // Filter out any unwanted results. - if (Filter && !(this->*Filter)(R.Declaration)) + if (Filter && !(this->*Filter)(ND)) { + // Check whether it is interesting as a nested-name-specifier. + if (AllowNestedNameSpecifiers && SemaRef.getLangOptions().CPlusPlus && + IsNestedNameSpecifier(ND) && + (Filter != &ResultBuilder::IsMember || + (isa(ND) && + cast(ND)->isInjectedClassName()))) { + AsNestedNameSpecifier = true; + return true; + } + + return false; + } + + // ... then it must be interesting! + return true; +} + +bool ResultBuilder::CheckHiddenResult(Result &R, DeclContext *CurContext, + NamedDecl *Hiding) { + // In C, there is no way to refer to a hidden name. + // FIXME: This isn't true; we can find a tag name hidden by an ordinary + // name if we introduce the tag type. + if (!SemaRef.getLangOptions().CPlusPlus) + return true; + + DeclContext *HiddenCtx = R.Declaration->getDeclContext()->getLookupContext(); + + // There is no way to qualify a name declared in a function or method. + if (HiddenCtx->isFunctionOrMethod()) + return true; + + if (HiddenCtx == Hiding->getDeclContext()->getLookupContext()) + return true; + + // We can refer to the result with the appropriate qualification. Do it. + R.Hidden = true; + R.QualifierIsInformative = false; + + if (!R.Qualifier) + R.Qualifier = getRequiredQualification(SemaRef.Context, + CurContext, + R.Declaration->getDeclContext()); + return false; +} + +void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { + assert(!ShadowMaps.empty() && "Must enter into a results scope"); + + if (R.Kind != Result::RK_Declaration) { + // For non-declaration results, just add the result. + Results.push_back(R); return; + } + + // Look through using declarations. + if (UsingShadowDecl *Using = dyn_cast(R.Declaration)) { + MaybeAddResult(Result(Using->getTargetDecl(), R.Qualifier), CurContext); + return; + } + Decl *CanonDecl = R.Declaration->getCanonicalDecl(); + unsigned IDNS = CanonDecl->getIdentifierNamespace(); + + bool AsNestedNameSpecifier = false; + if (!isInterestingDecl(R.Declaration, AsNestedNameSpecifier)) + return; + ShadowMap &SMap = ShadowMaps.back(); ShadowMapEntry::iterator I, IEnd; ShadowMap::iterator NamePos = SMap.find(R.Declaration->getDeclName()); @@ -406,9 +484,6 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { // This is a redeclaration. Always pick the newer declaration. Results[Index].Declaration = R.Declaration; - // Pick the best rank of the two. - Results[Index].Rank = std::min(Results[Index].Rank, R.Rank); - // We're done. return; } @@ -440,21 +515,8 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { continue; // The newly-added result is hidden by an entry in the shadow map. - if (canHiddenResultBeFound(SemaRef.getLangOptions(), R.Declaration, - I->first)) { - // Note that this result was hidden. - R.Hidden = true; - R.QualifierIsInformative = false; - - if (!R.Qualifier) - R.Qualifier = getRequiredQualification(SemaRef.Context, - CurContext, - R.Declaration->getDeclContext()); - } else { - // This result was hidden and cannot be found; don't bother adding - // it. + if (CheckHiddenResult(R, CurContext, I->first)) return; - } break; } @@ -466,10 +528,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { // If the filter is for nested-name-specifiers, then this result starts a // nested-name-specifier. - if ((Filter == &ResultBuilder::IsNestedNameSpecifier) || - (Filter == &ResultBuilder::IsMember && - isa(R.Declaration) && - cast(R.Declaration)->isInjectedClassName())) + if (AsNestedNameSpecifier) R.StartsNestedNameSpecifier = true; // If this result is supposed to have an informative qualifier, add one. @@ -491,6 +550,63 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { Results.push_back(R); } +void ResultBuilder::AddResult(Result R, DeclContext *CurContext, + NamedDecl *Hiding, bool InBaseClass = false) { + if (R.Kind != Result::RK_Declaration) { + // For non-declaration results, just add the result. + Results.push_back(R); + return; + } + + // Look through using declarations. + if (UsingShadowDecl *Using = dyn_cast(R.Declaration)) { + AddResult(Result(Using->getTargetDecl(), R.Qualifier), CurContext, Hiding); + return; + } + + bool AsNestedNameSpecifier = false; + if (!isInterestingDecl(R.Declaration, AsNestedNameSpecifier)) + return; + + if (Hiding && CheckHiddenResult(R, CurContext, Hiding)) + return; + + // Make sure that any given declaration only shows up in the result set once. + if (!AllDeclsFound.insert(R.Declaration->getCanonicalDecl())) + return; + + // If the filter is for nested-name-specifiers, then this result starts a + // nested-name-specifier. + if (AsNestedNameSpecifier) + R.StartsNestedNameSpecifier = true; + else if (Filter == &ResultBuilder::IsMember && !R.Qualifier && InBaseClass && + isa(R.Declaration->getDeclContext() + ->getLookupContext())) + R.QualifierIsInformative = true; + + // If this result is supposed to have an informative qualifier, add one. + if (R.QualifierIsInformative && !R.Qualifier && + !R.StartsNestedNameSpecifier) { + DeclContext *Ctx = R.Declaration->getDeclContext(); + if (NamespaceDecl *Namespace = dyn_cast(Ctx)) + R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, Namespace); + else if (TagDecl *Tag = dyn_cast(Ctx)) + R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, false, + SemaRef.Context.getTypeDeclType(Tag).getTypePtr()); + else + R.QualifierIsInformative = false; + } + + // Insert this result into the set of results. + Results.push_back(R); +} + +void ResultBuilder::AddResult(Result R) { + assert(R.Kind != Result::RK_Declaration && + "Declaration results need more context"); + Results.push_back(R); +} + /// \brief Enter into a new scope. void ResultBuilder::EnterNewScope() { ShadowMaps.push_back(ShadowMap()); @@ -513,10 +629,23 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const { unsigned IDNS = Decl::IDNS_Ordinary; if (SemaRef.getLangOptions().CPlusPlus) IDNS |= Decl::IDNS_Tag; - + else if (SemaRef.getLangOptions().ObjC1 && isa(ND)) + return true; + return ND->getIdentifierNamespace() & IDNS; } +/// \brief Determines whether this given declaration will be found by +/// ordinary name lookup. +bool ResultBuilder::IsOrdinaryNonValueName(NamedDecl *ND) const { + unsigned IDNS = Decl::IDNS_Ordinary; + if (SemaRef.getLangOptions().CPlusPlus) + IDNS |= Decl::IDNS_Tag; + + return (ND->getIdentifierNamespace() & IDNS) && + !isa(ND) && !isa(ND); +} + /// \brief Determines whether the given declaration is suitable as the /// start of a C++ nested-name-specifier, e.g., a class or namespace. bool ResultBuilder::IsNestedNameSpecifier(NamedDecl *ND) const { @@ -584,251 +713,601 @@ bool ResultBuilder::IsMember(NamedDecl *ND) const { isa(ND); } -// Find the next outer declaration context corresponding to this scope. -static DeclContext *findOuterContext(Scope *S) { - for (S = S->getParent(); S; S = S->getParent()) - if (S->getEntity()) - return static_cast(S->getEntity())->getPrimaryContext(); - - return 0; -} - -/// \brief Collect the results of searching for members within the given -/// declaration context. -/// -/// \param Ctx the declaration context from which we will gather results. -/// -/// \param Rank the rank given to results in this declaration context. -/// -/// \param Visited the set of declaration contexts that have already been -/// visited. Declaration contexts will only be visited once. -/// -/// \param Results the result set that will be extended with any results -/// found within this declaration context (and, for a C++ class, its bases). -/// -/// \param InBaseClass whether we are in a base class. -/// -/// \returns the next higher rank value, after considering all of the -/// names within this declaration context. -static unsigned CollectMemberLookupResults(DeclContext *Ctx, - unsigned Rank, - DeclContext *CurContext, - llvm::SmallPtrSet &Visited, - ResultBuilder &Results, - bool InBaseClass = false) { - // Make sure we don't visit the same context twice. - if (!Visited.insert(Ctx->getPrimaryContext())) - return Rank; - - // Enumerate all of the results in this context. - typedef CodeCompleteConsumer::Result Result; - Results.EnterNewScope(); - for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; - CurCtx = CurCtx->getNextContext()) { - for (DeclContext::decl_iterator D = CurCtx->decls_begin(), - DEnd = CurCtx->decls_end(); - D != DEnd; ++D) { - if (NamedDecl *ND = dyn_cast(*D)) - Results.MaybeAddResult(Result(ND, Rank, 0, InBaseClass), CurContext); - - // Visit transparent contexts inside this context. - if (DeclContext *InnerCtx = dyn_cast(*D)) { - if (InnerCtx->isTransparentContext()) - CollectMemberLookupResults(InnerCtx, Rank, CurContext, Visited, - Results, InBaseClass); - } - } - } - - // Traverse the contexts of inherited classes. - if (CXXRecordDecl *Record = dyn_cast(Ctx)) { - for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(), - BEnd = Record->bases_end(); - B != BEnd; ++B) { - QualType BaseType = B->getType(); - - // Don't look into dependent bases, because name lookup can't look - // there anyway. - if (BaseType->isDependentType()) - continue; - - const RecordType *Record = BaseType->getAs(); - if (!Record) - continue; - - // FIXME: It would be nice to be able to determine whether referencing - // a particular member would be ambiguous. For example, given - // - // struct A { int member; }; - // struct B { int member; }; - // struct C : A, B { }; - // - // void f(C *c) { c->### } - // accessing 'member' would result in an ambiguity. However, code - // completion could be smart enough to qualify the member with the - // base class, e.g., - // - // c->B::member - // - // or - // - // c->A::member - - // Collect results from this base class (and its bases). - CollectMemberLookupResults(Record->getDecl(), Rank, CurContext, Visited, - Results, /*InBaseClass=*/true); - } - } - - // FIXME: Look into base classes in Objective-C! - - Results.ExitScope(); - return Rank + 1; +/// \rief Determines whether the given declaration is an Objective-C +/// instance variable. +bool ResultBuilder::IsObjCIvar(NamedDecl *ND) const { + return isa(ND); } -/// \brief Collect the results of searching for members within the given -/// declaration context. -/// -/// \param Ctx the declaration context from which we will gather results. -/// -/// \param InitialRank the initial rank given to results in this declaration -/// context. Larger rank values will be used for, e.g., members found in -/// base classes. -/// -/// \param Results the result set that will be extended with any results -/// found within this declaration context (and, for a C++ class, its bases). -/// -/// \returns the next higher rank value, after considering all of the -/// names within this declaration context. -static unsigned CollectMemberLookupResults(DeclContext *Ctx, - unsigned InitialRank, - DeclContext *CurContext, - ResultBuilder &Results) { - llvm::SmallPtrSet Visited; - return CollectMemberLookupResults(Ctx, InitialRank, CurContext, Visited, - Results); -} - -/// \brief Collect the results of searching for declarations within the given -/// scope and its parent scopes. -/// -/// \param S the scope in which we will start looking for declarations. -/// -/// \param InitialRank the initial rank given to results in this scope. -/// Larger rank values will be used for results found in parent scopes. -/// -/// \param CurContext the context from which lookup results will be found. -/// -/// \param Results the builder object that will receive each result. -static unsigned CollectLookupResults(Scope *S, - TranslationUnitDecl *TranslationUnit, - unsigned InitialRank, - DeclContext *CurContext, - ResultBuilder &Results) { - if (!S) - return InitialRank; - - // FIXME: Using directives! - - unsigned NextRank = InitialRank; - Results.EnterNewScope(); - if (S->getEntity() && - !((DeclContext *)S->getEntity())->isFunctionOrMethod()) { - // Look into this scope's declaration context, along with any of its - // parent lookup contexts (e.g., enclosing classes), up to the point - // where we hit the context stored in the next outer scope. - DeclContext *Ctx = (DeclContext *)S->getEntity(); - DeclContext *OuterCtx = findOuterContext(S); - - for (; Ctx && Ctx->getPrimaryContext() != OuterCtx; - Ctx = Ctx->getLookupParent()) { - if (Ctx->isFunctionOrMethod()) - continue; - - NextRank = CollectMemberLookupResults(Ctx, NextRank + 1, CurContext, - Results); - } - } else if (!S->getParent()) { - // Look into the translation unit scope. We walk through the translation - // unit's declaration context, because the Scope itself won't have all of - // the declarations if we loaded a precompiled header. - // FIXME: We would like the translation unit's Scope object to point to the - // translation unit, so we don't need this special "if" branch. However, - // doing so would force the normal C++ name-lookup code to look into the - // translation unit decl when the IdentifierInfo chains would suffice. - // Once we fix that problem (which is part of a more general "don't look - // in DeclContexts unless we have to" optimization), we can eliminate the - // TranslationUnit parameter entirely. - NextRank = CollectMemberLookupResults(TranslationUnit, NextRank + 1, - CurContext, Results); - } else { - // Walk through the declarations in this Scope. - for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); - D != DEnd; ++D) { - if (NamedDecl *ND = dyn_cast((Decl *)((*D).get()))) - Results.MaybeAddResult(CodeCompleteConsumer::Result(ND, NextRank), - CurContext); - } +namespace { + /// \brief Visible declaration consumer that adds a code-completion result + /// for each visible declaration. + class CodeCompletionDeclConsumer : public VisibleDeclConsumer { + ResultBuilder &Results; + DeclContext *CurContext; - NextRank = NextRank + 1; - } - - // Lookup names in the parent scope. - NextRank = CollectLookupResults(S->getParent(), TranslationUnit, NextRank, - CurContext, Results); - Results.ExitScope(); - - return NextRank; + public: + CodeCompletionDeclConsumer(ResultBuilder &Results, DeclContext *CurContext) + : Results(Results), CurContext(CurContext) { } + + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass) { + Results.AddResult(ND, CurContext, Hiding, InBaseClass); + } + }; } /// \brief Add type specifiers for the current language as keyword results. -static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank, +static void AddTypeSpecifierResults(const LangOptions &LangOpts, ResultBuilder &Results) { typedef CodeCompleteConsumer::Result Result; - Results.MaybeAddResult(Result("short", Rank)); - Results.MaybeAddResult(Result("long", Rank)); - Results.MaybeAddResult(Result("signed", Rank)); - Results.MaybeAddResult(Result("unsigned", Rank)); - Results.MaybeAddResult(Result("void", Rank)); - Results.MaybeAddResult(Result("char", Rank)); - Results.MaybeAddResult(Result("int", Rank)); - Results.MaybeAddResult(Result("float", Rank)); - Results.MaybeAddResult(Result("double", Rank)); - Results.MaybeAddResult(Result("enum", Rank)); - Results.MaybeAddResult(Result("struct", Rank)); - Results.MaybeAddResult(Result("union", Rank)); - + Results.AddResult(Result("short")); + Results.AddResult(Result("long")); + Results.AddResult(Result("signed")); + Results.AddResult(Result("unsigned")); + Results.AddResult(Result("void")); + Results.AddResult(Result("char")); + Results.AddResult(Result("int")); + Results.AddResult(Result("float")); + Results.AddResult(Result("double")); + Results.AddResult(Result("enum")); + Results.AddResult(Result("struct")); + Results.AddResult(Result("union")); + Results.AddResult(Result("const")); + Results.AddResult(Result("volatile")); + if (LangOpts.C99) { // C99-specific - Results.MaybeAddResult(Result("_Complex", Rank)); - Results.MaybeAddResult(Result("_Imaginary", Rank)); - Results.MaybeAddResult(Result("_Bool", Rank)); + Results.AddResult(Result("_Complex")); + Results.AddResult(Result("_Imaginary")); + Results.AddResult(Result("_Bool")); + Results.AddResult(Result("restrict")); } if (LangOpts.CPlusPlus) { // C++-specific - Results.MaybeAddResult(Result("bool", Rank)); - Results.MaybeAddResult(Result("class", Rank)); - Results.MaybeAddResult(Result("typename", Rank)); - Results.MaybeAddResult(Result("wchar_t", Rank)); + Results.AddResult(Result("bool")); + Results.AddResult(Result("class")); + Results.AddResult(Result("wchar_t")); + // typename qualified-id + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("typename"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("qualified-id"); + Results.AddResult(Result(Pattern)); + if (LangOpts.CPlusPlus0x) { - Results.MaybeAddResult(Result("char16_t", Rank)); - Results.MaybeAddResult(Result("char32_t", Rank)); - Results.MaybeAddResult(Result("decltype", Rank)); + Results.AddResult(Result("auto")); + Results.AddResult(Result("char16_t")); + Results.AddResult(Result("char32_t")); + Results.AddResult(Result("decltype")); } } // GNU extensions if (LangOpts.GNUMode) { // FIXME: Enable when we actually support decimal floating point. - // Results.MaybeAddResult(Result("_Decimal32", Rank)); - // Results.MaybeAddResult(Result("_Decimal64", Rank)); - // Results.MaybeAddResult(Result("_Decimal128", Rank)); - Results.MaybeAddResult(Result("typeof", Rank)); + // Results.AddResult(Result("_Decimal32")); + // Results.AddResult(Result("_Decimal64")); + // Results.AddResult(Result("_Decimal128")); + + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("typeof"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); } } +static void AddStorageSpecifiers(Action::CodeCompletionContext CCC, + const LangOptions &LangOpts, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + // Note: we don't suggest either "auto" or "register", because both + // are pointless as storage specifiers. Elsewhere, we suggest "auto" + // in C++0x as a type specifier. + Results.AddResult(Result("extern")); + Results.AddResult(Result("static")); +} + +static void AddFunctionSpecifiers(Action::CodeCompletionContext CCC, + const LangOptions &LangOpts, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + switch (CCC) { + case Action::CCC_Class: + case Action::CCC_MemberTemplate: + if (LangOpts.CPlusPlus) { + Results.AddResult(Result("explicit")); + Results.AddResult(Result("friend")); + Results.AddResult(Result("mutable")); + Results.AddResult(Result("virtual")); + } + // Fall through + + case Action::CCC_ObjCInterface: + case Action::CCC_ObjCImplementation: + case Action::CCC_Namespace: + case Action::CCC_Template: + if (LangOpts.CPlusPlus || LangOpts.C99) + Results.AddResult(Result("inline")); + break; + + case Action::CCC_ObjCInstanceVariableList: + case Action::CCC_Expression: + case Action::CCC_Statement: + case Action::CCC_ForInit: + case Action::CCC_Condition: + break; + } +} + +static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt); +static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt); +static void AddObjCVisibilityResults(const LangOptions &LangOpts, + ResultBuilder &Results, + bool NeedAt); +static void AddObjCImplementationResults(const LangOptions &LangOpts, + ResultBuilder &Results, + bool NeedAt); +static void AddObjCInterfaceResults(const LangOptions &LangOpts, + ResultBuilder &Results, + bool NeedAt); +static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt); + +/// \brief Add language constructs that show up for "ordinary" names. +static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, + Scope *S, + Sema &SemaRef, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + switch (CCC) { + case Action::CCC_Namespace: + if (SemaRef.getLangOptions().CPlusPlus) { + // namespace { } + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("namespace"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("declarations"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + + // namespace identifier = identifier ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("namespace"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_Equal); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + + // Using directives + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("using"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("namespace"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + + // asm(string-literal) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("asm"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("string-literal"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + + // Explicit template instantiation + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("template"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("declaration"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + } + + if (SemaRef.getLangOptions().ObjC1) + AddObjCTopLevelResults(Results, true); + + // Fall through + + case Action::CCC_Class: + Results.AddResult(Result("typedef")); + if (SemaRef.getLangOptions().CPlusPlus) { + // Using declaration + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("using"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("qualified-id"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + + // using typename qualified-id; (only in a dependent context) + if (SemaRef.CurContext->isDependentContext()) { + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("using"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("typename"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("qualified-id"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + } + + if (CCC == Action::CCC_Class) { + // public: + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("public"); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + Results.AddResult(Result(Pattern)); + + // protected: + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("protected"); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + Results.AddResult(Result(Pattern)); + + // private: + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("private"); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + Results.AddResult(Result(Pattern)); + } + } + // Fall through + + case Action::CCC_Template: + case Action::CCC_MemberTemplate: + if (SemaRef.getLangOptions().CPlusPlus) { + // template < parameters > + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("template"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("parameters"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Results.AddResult(Result(Pattern)); + } + + AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results); + AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results); + break; + + case Action::CCC_ObjCInterface: + AddObjCInterfaceResults(SemaRef.getLangOptions(), Results, true); + AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results); + AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results); + break; + + case Action::CCC_ObjCImplementation: + AddObjCImplementationResults(SemaRef.getLangOptions(), Results, true); + AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results); + AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results); + break; + + case Action::CCC_ObjCInstanceVariableList: + AddObjCVisibilityResults(SemaRef.getLangOptions(), Results, true); + break; + + case Action::CCC_Statement: { + Results.AddResult(Result("typedef")); + + CodeCompletionString *Pattern = 0; + if (SemaRef.getLangOptions().CPlusPlus) { + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("try"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Pattern->AddTextChunk("catch"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("declaration"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + } + if (SemaRef.getLangOptions().ObjC1) + AddObjCStatementResults(Results, true); + + // if (condition) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("if"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus) + Pattern->AddPlaceholderChunk("condition"); + else + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + + // switch (condition) { } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("switch"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus) + Pattern->AddPlaceholderChunk("condition"); + else + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + + // Switch-specific statements. + if (!SemaRef.getSwitchStack().empty()) { + // case expression: + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("case"); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + Results.AddResult(Result(Pattern)); + + // default: + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("default"); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + Results.AddResult(Result(Pattern)); + } + + /// while (condition) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("while"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus) + Pattern->AddPlaceholderChunk("condition"); + else + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + + // do { statements } while ( expression ); + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("do"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Pattern->AddTextChunk("while"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + + // for ( for-init-statement ; condition ; expression ) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("for"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus || SemaRef.getLangOptions().C99) + Pattern->AddPlaceholderChunk("init-statement"); + else + Pattern->AddPlaceholderChunk("init-expression"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Pattern->AddPlaceholderChunk("condition"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Pattern->AddPlaceholderChunk("inc-expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + + if (S->getContinueParent()) { + // continue ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("continue"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + } + + if (S->getBreakParent()) { + // break ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("break"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + } + + // "return expression ;" or "return ;", depending on whether we + // know the function is void or not. + bool isVoid = false; + if (FunctionDecl *Function = dyn_cast(SemaRef.CurContext)) + isVoid = Function->getResultType()->isVoidType(); + else if (ObjCMethodDecl *Method + = dyn_cast(SemaRef.CurContext)) + isVoid = Method->getResultType()->isVoidType(); + else if (SemaRef.CurBlock && !SemaRef.CurBlock->ReturnType.isNull()) + isVoid = SemaRef.CurBlock->ReturnType->isVoidType(); + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("return"); + if (!isVoid) + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + + // goto identifier ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("goto"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + + // Using directives + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("using"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("namespace"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + } + + // Fall through (for statement expressions). + case Action::CCC_ForInit: + case Action::CCC_Condition: + AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results); + // Fall through: conditions and statements can have expressions. + + case Action::CCC_Expression: { + CodeCompletionString *Pattern = 0; + if (SemaRef.getLangOptions().CPlusPlus) { + // 'this', if we're in a non-static member function. + if (CXXMethodDecl *Method = dyn_cast(SemaRef.CurContext)) + if (!Method->isStatic()) + Results.AddResult(Result("this")); + + // true, false + Results.AddResult(Result("true")); + Results.AddResult(Result("false")); + + // dynamic_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("dynamic_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // static_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("static_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // reinterpret_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("reinterpret_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // const_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("const_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // typeid ( expression-or-type ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("typeid"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // new T ( ... ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("new"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expressions"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // new T [ ] ( ... ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("new"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBracket); + Pattern->AddPlaceholderChunk("size"); + Pattern->AddChunk(CodeCompletionString::CK_RightBracket); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expressions"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // delete expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("delete"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Results.AddResult(Result(Pattern)); + + // delete [] expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("delete"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBracket); + Pattern->AddChunk(CodeCompletionString::CK_RightBracket); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Results.AddResult(Result(Pattern)); + + // throw expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("throw"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Results.AddResult(Result(Pattern)); + } + + if (SemaRef.getLangOptions().ObjC1) { + // Add "super", if we're in an Objective-C class with a superclass. + if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) + if (Method->getClassInterface()->getSuperClass()) + Results.AddResult(Result("super")); + + AddObjCExpressionResults(Results, true); + } + + // sizeof expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("sizeof"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + break; + } + } + + AddTypeSpecifierResults(SemaRef.getLangOptions(), Results); + + if (SemaRef.getLangOptions().CPlusPlus) + Results.AddResult(Result("operator")); +} + /// \brief If the given declaration has an associated type, add it as a result /// type chunk. static void AddResultTypeChunk(ASTContext &Context, @@ -1178,7 +1657,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { if (Idx > 0) { std::string Keyword; if (Idx > StartParameter) - Keyword = " "; + Result->AddChunk(CodeCompletionString::CK_HorizontalSpace); if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx)) Keyword += II->getName().str(); Keyword += ":"; @@ -1344,29 +1823,49 @@ namespace { Y.getAsString()) < 0; } - bool operator()(const Result &X, const Result &Y) const { - // Sort first by rank. - if (X.Rank < Y.Rank) - return true; - else if (X.Rank > Y.Rank) - return false; - - // We use a special ordering for keywords and patterns, based on the - // typed text. - if ((X.Kind == Result::RK_Keyword || X.Kind == Result::RK_Pattern) && - (Y.Kind == Result::RK_Keyword || Y.Kind == Result::RK_Pattern)) { - const char *XStr = (X.Kind == Result::RK_Keyword)? X.Keyword - : X.Pattern->getTypedText(); - const char *YStr = (Y.Kind == Result::RK_Keyword)? Y.Keyword - : Y.Pattern->getTypedText(); - return llvm::StringRef(XStr).compare_lower(YStr) < 0; + /// \brief Retrieve the name that should be used to order a result. + /// + /// If the name needs to be constructed as a string, that string will be + /// saved into Saved and the returned StringRef will refer to it. + static llvm::StringRef getOrderedName(const Result &R, + std::string &Saved) { + switch (R.Kind) { + case Result::RK_Keyword: + return R.Keyword; + + case Result::RK_Pattern: + return R.Pattern->getTypedText(); + + case Result::RK_Macro: + return R.Macro->getName(); + + case Result::RK_Declaration: + // Handle declarations below. + break; } + + DeclarationName Name = R.Declaration->getDeclName(); - // Result kinds are ordered by decreasing importance. - if (X.Kind < Y.Kind) - return true; - else if (X.Kind > Y.Kind) - return false; + // If the name is a simple identifier (by far the common case), or a + // zero-argument selector, just return a reference to that identifier. + if (IdentifierInfo *Id = Name.getAsIdentifierInfo()) + return Id->getName(); + if (Name.isObjCZeroArgSelector()) + if (IdentifierInfo *Id + = Name.getObjCSelector().getIdentifierInfoForSlot(0)) + return Id->getName(); + + Saved = Name.getAsString(); + return Saved; + } + + bool operator()(const Result &X, const Result &Y) const { + std::string XSaved, YSaved; + llvm::StringRef XStr = getOrderedName(X, XSaved); + llvm::StringRef YStr = getOrderedName(Y, YSaved); + int cmp = XStr.compare_lower(YStr); + if (cmp) + return cmp < 0; // Non-hidden names precede hidden names. if (X.Hidden != Y.Hidden) @@ -1376,35 +1875,17 @@ namespace { if (X.StartsNestedNameSpecifier != Y.StartsNestedNameSpecifier) return !X.StartsNestedNameSpecifier; - // Ordering depends on the kind of result. - switch (X.Kind) { - case Result::RK_Declaration: - // Order based on the declaration names. - return isEarlierDeclarationName(X.Declaration->getDeclName(), - Y.Declaration->getDeclName()); - - case Result::RK_Macro: - return X.Macro->getName().compare_lower(Y.Macro->getName()) < 0; - - case Result::RK_Keyword: - case Result::RK_Pattern: - llvm_unreachable("Result kinds handled above"); - break; - } - - // Silence GCC warning. return false; } }; } -static void AddMacroResults(Preprocessor &PP, unsigned Rank, - ResultBuilder &Results) { +static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results) { Results.EnterNewScope(); for (Preprocessor::macro_iterator M = PP.macro_begin(), MEnd = PP.macro_end(); M != MEnd; ++M) - Results.MaybeAddResult(CodeCompleteConsumer::Result(M->first, Rank)); + Results.AddResult(M->first); Results.ExitScope(); } @@ -1412,7 +1893,6 @@ static void HandleCodeCompleteResults(Sema *S, CodeCompleteConsumer *CodeCompleter, CodeCompleteConsumer::Result *Results, unsigned NumResults) { - // Sort the results by rank/kind/etc. std::stable_sort(Results, Results + NumResults, SortCodeCompleteResult()); if (CodeCompleter) @@ -1422,26 +1902,42 @@ static void HandleCodeCompleteResults(Sema *S, Results[I].Destroy(); } -void Sema::CodeCompleteOrdinaryName(Scope *S) { +void Sema::CodeCompleteOrdinaryName(Scope *S, + CodeCompletionContext CompletionContext) { typedef CodeCompleteConsumer::Result Result; - ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName); - unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), - 0, CurContext, Results); + ResultBuilder Results(*this); - Results.EnterNewScope(); - AddTypeSpecifierResults(getLangOptions(), NextRank, Results); - - if (getLangOptions().ObjC1) { - // Add the "super" keyword, if appropriate. - if (ObjCMethodDecl *Method = dyn_cast(CurContext)) - if (Method->getClassInterface()->getSuperClass()) - Results.MaybeAddResult(Result("super", NextRank)); + // Determine how to filter results, e.g., so that the names of + // values (functions, enumerators, function templates, etc.) are + // only allowed where we can have an expression. + switch (CompletionContext) { + case CCC_Namespace: + case CCC_Class: + case CCC_ObjCInterface: + case CCC_ObjCImplementation: + case CCC_ObjCInstanceVariableList: + case CCC_Template: + case CCC_MemberTemplate: + Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName); + break; + + case CCC_Expression: + case CCC_Statement: + case CCC_ForInit: + case CCC_Condition: + Results.setFilter(&ResultBuilder::IsOrdinaryName); + break; } + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer); + + Results.EnterNewScope(); + AddOrdinaryNameResults(CompletionContext, S, *this, Results); Results.ExitScope(); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -1513,13 +2009,12 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, } ResultBuilder Results(*this, &ResultBuilder::IsMember); - unsigned NextRank = 0; - Results.EnterNewScope(); if (const RecordType *Record = BaseType->getAs()) { // Access to a C/C++ class, struct, or union. - NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank, - Record->getDecl(), Results); + Results.allowNestedNameSpecifiers(); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(Record->getDecl(), LookupMemberName, Consumer); if (getLangOptions().CPlusPlus) { if (!Results.empty()) { @@ -1536,16 +2031,8 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, } if (IsDependent) - Results.MaybeAddResult(Result("template", NextRank++)); + Results.AddResult(Result("template")); } - - // We could have the start of a nested-name-specifier. Add those - // results as well. - // FIXME: We should really walk base classes to produce - // nested-name-specifiers so that we produce more-precise results. - Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank, - CurContext, Results); } } else if (!IsArrow && BaseType->getAsObjCInterfacePointerType()) { // Objective-C property reference. @@ -1561,9 +2048,6 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, E = ObjCPtr->qual_end(); I != E; ++I) AddObjCProperties(*I, true, CurContext, Results); - - // FIXME: We could (should?) also look for "implicit" properties, identified - // only by the presence of nullary and unary selectors. } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || (!IsArrow && BaseType->isObjCInterfaceType())) { // Objective-C instance variable access. @@ -1575,11 +2059,10 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, Class = BaseType->getAs()->getDecl(); // Add all ivars from this class and its superclasses. - for (; Class; Class = Class->getSuperClass()) { - for (ObjCInterfaceDecl::ivar_iterator IVar = Class->ivar_begin(), - IVarEnd = Class->ivar_end(); - IVar != IVarEnd; ++IVar) - Results.MaybeAddResult(Result(*IVar, 0), CurContext); + if (Class) { + CodeCompletionDeclConsumer Consumer(Results, CurContext); + Results.setFilter(&ResultBuilder::IsObjCIvar); + LookupVisibleDecls(Class, LookupMemberName, Consumer); } } @@ -1589,7 +2072,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, // Add macros if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank, Results); + AddMacroResults(PP, Results); // Hand off the results found for code completion. HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); @@ -1621,19 +2104,12 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { } ResultBuilder Results(*this, Filter); - unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), - 0, CurContext, Results); - - if (getLangOptions().CPlusPlus) { - // We could have the start of a nested-name-specifier. Add those - // results as well. - Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), - NextRank, CurContext, Results); - } + Results.allowNestedNameSpecifiers(); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupTagName, Consumer); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -1707,12 +2183,13 @@ void Sema::CodeCompleteCase(Scope *S) { if (EnumeratorsSeen.count(*E)) continue; - Results.MaybeAddResult(CodeCompleteConsumer::Result(*E, 0, Qualifier)); + Results.AddResult(CodeCompleteConsumer::Result(*E, Qualifier), + CurContext, 0, false); } Results.ExitScope(); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, 1, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -1746,7 +2223,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, // Ignore type-dependent call expressions entirely. if (Fn->isTypeDependent() || Expr::hasAnyTypeDependentArguments(Args, NumArgs)) { - CodeCompleteOrdinaryName(S); + CodeCompleteOrdinaryName(S, CCC_Expression); return; } @@ -1784,7 +2261,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, } if (Results.empty()) - CodeCompleteOrdinaryName(S); + CodeCompleteOrdinaryName(S, CCC_Expression); else CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(), Results.size()); @@ -1805,16 +2282,17 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, return; ResultBuilder Results(*this); - unsigned NextRank = CollectMemberLookupResults(Ctx, 0, Ctx, Results); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer); // The "template" keyword can follow "::" in the grammar, but only // put it into the grammar if the nested-name-specifier is dependent. NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); if (!Results.empty() && NNS->isDependent()) - Results.MaybeAddResult(CodeCompleteConsumer::Result("template", NextRank)); + Results.AddResult("template"); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank + 1, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -1827,16 +2305,16 @@ void Sema::CodeCompleteUsing(Scope *S) { // If we aren't in class scope, we could see the "namespace" keyword. if (!S->isClassScope()) - Results.MaybeAddResult(CodeCompleteConsumer::Result("namespace", 0)); + Results.AddResult(CodeCompleteConsumer::Result("namespace")); // After "using", we can see anything that would start a // nested-name-specifier. - unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), - 0, CurContext, Results); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer); Results.ExitScope(); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -1848,11 +2326,11 @@ void Sema::CodeCompleteUsingDirective(Scope *S) { // alias. ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); Results.EnterNewScope(); - unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), - 0, CurContext, Results); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer); Results.ExitScope(); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -1882,13 +2360,13 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) { for (std::map::iterator NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end(); NS != NSEnd; ++NS) - Results.MaybeAddResult(CodeCompleteConsumer::Result(NS->second, 0), - CurContext); + Results.AddResult(CodeCompleteConsumer::Result(NS->second, 0), + CurContext, 0, false); Results.ExitScope(); } if (CodeCompleter->includeMacros()) - AddMacroResults(PP, 1, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -1898,10 +2376,10 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { // After "namespace", we expect to see a namespace or alias. ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); - unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), - 0, CurContext, Results); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -1916,155 +2394,168 @@ void Sema::CodeCompleteOperatorName(Scope *S) { // Add the names of overloadable operators. #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ if (std::strcmp(Spelling, "?")) \ - Results.MaybeAddResult(Result(Spelling, 0)); + Results.AddResult(Result(Spelling)); #include "clang/Basic/OperatorKinds.def" // Add any type names visible from the current scope - unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), - 0, CurContext, Results); + Results.allowNestedNameSpecifiers(); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer); // Add any type specifiers - AddTypeSpecifierResults(getLangOptions(), 0, Results); - - // Add any nested-name-specifiers - Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), - NextRank + 1, CurContext, Results); + AddTypeSpecifierResults(getLangOptions(), Results); Results.ExitScope(); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } -void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, - bool InInterface) { +// Macro that expands to @Keyword or Keyword, depending on whether NeedAt is +// true or false. +#define OBJC_AT_KEYWORD_NAME(NeedAt,Keyword) NeedAt? "@" #Keyword : #Keyword +static void AddObjCImplementationResults(const LangOptions &LangOpts, + ResultBuilder &Results, + bool NeedAt) { typedef CodeCompleteConsumer::Result Result; - ResultBuilder Results(*this); - Results.EnterNewScope(); - if (ObjCImpDecl) { - // Since we have an implementation, we can end it. - Results.MaybeAddResult(Result("end", 0)); - - CodeCompletionString *Pattern = 0; - Decl *ImpDecl = ObjCImpDecl.getAs(); - if (isa(ImpDecl) || - isa(ImpDecl)) { - // @dynamic - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("dynamic"); - Pattern->AddTextChunk(" "); - Pattern->AddPlaceholderChunk("property"); - Results.MaybeAddResult(Result(Pattern, 0)); - - // @synthesize - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("synthesize"); - Pattern->AddTextChunk(" "); - Pattern->AddPlaceholderChunk("property"); - Results.MaybeAddResult(Result(Pattern, 0)); - } - } else if (InInterface) { - // Since we have an interface or protocol, we can end it. - Results.MaybeAddResult(Result("end", 0)); - - if (LangOpts.ObjC2) { - // @property - Results.MaybeAddResult(Result("property", 0)); - } - - // @required - Results.MaybeAddResult(Result("required", 0)); - - // @optional - Results.MaybeAddResult(Result("optional", 0)); - } else { - CodeCompletionString *Pattern = 0; - - // @class name ; + // Since we have an implementation, we can end it. + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end))); + + CodeCompletionString *Pattern = 0; + if (LangOpts.ObjC2) { + // @dynamic Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("class"); - Pattern->AddTextChunk(" "); - Pattern->AddPlaceholderChunk("identifier"); - Pattern->AddTextChunk(";"); // add ';' chunk - Results.MaybeAddResult(Result(Pattern, 0)); - - // @interface name - // FIXME: Could introduce the whole pattern, including superclasses and - // such. + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,dynamic)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("property"); + Results.AddResult(Result(Pattern)); + + // @synthesize Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("interface"); - Pattern->AddTextChunk(" "); - Pattern->AddPlaceholderChunk("class"); - Results.MaybeAddResult(Result(Pattern, 0)); + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,synthesize)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("property"); + Results.AddResult(Result(Pattern)); + } +} - // @protocol name - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("protocol"); - Pattern->AddTextChunk(" "); - Pattern->AddPlaceholderChunk("protocol"); - Results.MaybeAddResult(Result(Pattern, 0)); +static void AddObjCInterfaceResults(const LangOptions &LangOpts, + ResultBuilder &Results, + bool NeedAt) { + typedef CodeCompleteConsumer::Result Result; + + // Since we have an interface or protocol, we can end it. + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end))); + + if (LangOpts.ObjC2) { + // @property + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,property))); + + // @required + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,required))); + + // @optional + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,optional))); + } +} - // @implementation name - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("implementation"); - Pattern->AddTextChunk(" "); - Pattern->AddPlaceholderChunk("class"); - Results.MaybeAddResult(Result(Pattern, 0)); +static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) { + typedef CodeCompleteConsumer::Result Result; + CodeCompletionString *Pattern = 0; + + // @class name ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,class)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + + // @interface name + // FIXME: Could introduce the whole pattern, including superclasses and + // such. + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,interface)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("class"); + Results.AddResult(Result(Pattern)); + + // @protocol name + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,protocol)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("protocol"); + Results.AddResult(Result(Pattern)); + + // @implementation name + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,implementation)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("class"); + Results.AddResult(Result(Pattern)); + + // @compatibility_alias name + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,compatibility_alias)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("alias"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("class"); + Results.AddResult(Result(Pattern)); +} - // @compatibility_alias name - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("compatibility_alias"); - Pattern->AddTextChunk(" "); - Pattern->AddPlaceholderChunk("alias"); - Pattern->AddTextChunk(" "); - Pattern->AddPlaceholderChunk("class"); - Results.MaybeAddResult(Result(Pattern, 0)); - } +void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, + bool InInterface) { + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this); + Results.EnterNewScope(); + if (ObjCImpDecl) + AddObjCImplementationResults(getLangOptions(), Results, false); + else if (InInterface) + AddObjCInterfaceResults(getLangOptions(), Results, false); + else + AddObjCTopLevelResults(Results, false); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } -static void AddObjCExpressionResults(unsigned Rank, ResultBuilder &Results) { +static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) { typedef CodeCompleteConsumer::Result Result; CodeCompletionString *Pattern = 0; // @encode ( type-name ) Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("encode"); + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,encode)); Pattern->AddChunk(CodeCompletionString::CK_LeftParen); Pattern->AddPlaceholderChunk("type-name"); Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.MaybeAddResult(Result(Pattern, Rank)); + Results.AddResult(Result(Pattern)); // @protocol ( protocol-name ) Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("protocol"); + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,protocol)); Pattern->AddChunk(CodeCompletionString::CK_LeftParen); Pattern->AddPlaceholderChunk("protocol-name"); Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.MaybeAddResult(Result(Pattern, Rank)); + Results.AddResult(Result(Pattern)); // @selector ( selector ) Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("selector"); + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,selector)); Pattern->AddChunk(CodeCompletionString::CK_LeftParen); Pattern->AddPlaceholderChunk("selector"); Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.MaybeAddResult(Result(Pattern, Rank)); + Results.AddResult(Result(Pattern)); } -void Sema::CodeCompleteObjCAtStatement(Scope *S) { +static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) { typedef CodeCompleteConsumer::Result Result; - ResultBuilder Results(*this); - Results.EnterNewScope(); - CodeCompletionString *Pattern = 0; - + // @try { statements } @catch ( declaration ) { statements } @finally // { statements } Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("try"); + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,try)); Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); Pattern->AddPlaceholderChunk("statements"); Pattern->AddChunk(CodeCompletionString::CK_RightBrace); @@ -2079,29 +2570,53 @@ void Sema::CodeCompleteObjCAtStatement(Scope *S) { Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); Pattern->AddPlaceholderChunk("statements"); Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.MaybeAddResult(Result(Pattern, 0)); - + Results.AddResult(Result(Pattern)); + // @throw Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("throw"); - Pattern->AddTextChunk(" "); + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,throw)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("expression"); - Pattern->AddTextChunk(";"); - Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk - + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + // @synchronized ( expression ) { statements } Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("synchronized"); - Pattern->AddTextChunk(" "); + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,synchronized)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddChunk(CodeCompletionString::CK_LeftParen); Pattern->AddPlaceholderChunk("expression"); Pattern->AddChunk(CodeCompletionString::CK_RightParen); Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); Pattern->AddPlaceholderChunk("statements"); Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk + Results.AddResult(Result(Pattern)); +} + +static void AddObjCVisibilityResults(const LangOptions &LangOpts, + ResultBuilder &Results, + bool NeedAt) { + typedef CodeCompleteConsumer::Result Result; + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,private))); + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,protected))); + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,public))); + if (LangOpts.ObjC2) + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,package))); +} - AddObjCExpressionResults(0, Results); +void Sema::CodeCompleteObjCAtVisibility(Scope *S) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + AddObjCVisibilityResults(getLangOptions(), Results, false); + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCAtStatement(Scope *S) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + AddObjCStatementResults(Results, false); + AddObjCExpressionResults(Results, false); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2109,7 +2624,7 @@ void Sema::CodeCompleteObjCAtStatement(Scope *S) { void Sema::CodeCompleteObjCAtExpression(Scope *S) { ResultBuilder Results(*this); Results.EnterNewScope(); - AddObjCExpressionResults(0, Results); + AddObjCExpressionResults(Results, false); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2154,30 +2669,30 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { ResultBuilder Results(*this); Results.EnterNewScope(); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readonly)) - Results.MaybeAddResult(CodeCompleteConsumer::Result("readonly", 0)); + Results.AddResult(CodeCompleteConsumer::Result("readonly")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_assign)) - Results.MaybeAddResult(CodeCompleteConsumer::Result("assign", 0)); + Results.AddResult(CodeCompleteConsumer::Result("assign")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readwrite)) - Results.MaybeAddResult(CodeCompleteConsumer::Result("readwrite", 0)); + Results.AddResult(CodeCompleteConsumer::Result("readwrite")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_retain)) - Results.MaybeAddResult(CodeCompleteConsumer::Result("retain", 0)); + Results.AddResult(CodeCompleteConsumer::Result("retain")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_copy)) - Results.MaybeAddResult(CodeCompleteConsumer::Result("copy", 0)); + Results.AddResult(CodeCompleteConsumer::Result("copy")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic)) - Results.MaybeAddResult(CodeCompleteConsumer::Result("nonatomic", 0)); + Results.AddResult(CodeCompleteConsumer::Result("nonatomic")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) { CodeCompletionString *Setter = new CodeCompletionString; Setter->AddTypedTextChunk("setter"); Setter->AddTextChunk(" = "); Setter->AddPlaceholderChunk("method"); - Results.MaybeAddResult(CodeCompleteConsumer::Result(Setter, 0)); + Results.AddResult(CodeCompleteConsumer::Result(Setter)); } if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_getter)) { CodeCompletionString *Getter = new CodeCompletionString; Getter->AddTypedTextChunk("getter"); Getter->AddTextChunk(" = "); Getter->AddPlaceholderChunk("method"); - Results.MaybeAddResult(CodeCompleteConsumer::Result(Getter, 0)); + Results.AddResult(CodeCompleteConsumer::Result(Getter)); } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); @@ -2522,7 +3037,7 @@ static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext, // Record any protocols we find. if (ObjCProtocolDecl *Proto = dyn_cast(*D)) if (!OnlyForwardDeclarations || Proto->isForwardDecl()) - Results.MaybeAddResult(Result(Proto, 0), CurContext); + Results.AddResult(Result(Proto, 0), CurContext, 0, false); // Record any forward-declared protocols we find. if (ObjCForwardProtocolDecl *Forward @@ -2532,7 +3047,7 @@ static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext, PEnd = Forward->protocol_end(); P != PEnd; ++P) if (!OnlyForwardDeclarations || (*P)->isForwardDecl()) - Results.MaybeAddResult(Result(*P, 0), CurContext); + Results.AddResult(Result(*P, 0), CurContext, 0, false); } } } @@ -2583,7 +3098,7 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext, if (ObjCInterfaceDecl *Class = dyn_cast(*D)) if ((!OnlyForwardDeclarations || Class->isForwardDecl()) && (!OnlyUnimplemented || !Class->getImplementation())) - Results.MaybeAddResult(Result(Class, 0), CurContext); + Results.AddResult(Result(Class, 0), CurContext, 0, false); // Record any forward-declared interfaces we find. if (ObjCClassDecl *Forward = dyn_cast(*D)) { @@ -2591,7 +3106,8 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext, C != CEnd; ++C) if ((!OnlyForwardDeclarations || C->getInterface()->isForwardDecl()) && (!OnlyUnimplemented || !C->getInterface()->getImplementation())) - Results.MaybeAddResult(Result(C->getInterface(), 0), CurContext); + Results.AddResult(Result(C->getInterface(), 0), CurContext, + 0, false); } } } @@ -2662,7 +3178,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, D != DEnd; ++D) if (ObjCCategoryDecl *Category = dyn_cast(*D)) if (CategoryNames.insert(Category->getIdentifier())) - Results.MaybeAddResult(Result(Category, 0), CurContext); + Results.AddResult(Result(Category, 0), CurContext, 0, false); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); @@ -2694,7 +3210,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, Category = Category->getNextClassCategory()) if ((!IgnoreImplemented || !Category->getImplementation()) && CategoryNames.insert(Category->getIdentifier())) - Results.MaybeAddResult(Result(Category, 0), CurContext); + Results.AddResult(Result(Category, 0), CurContext, 0, false); Class = Class->getSuperClass(); IgnoreImplemented = false; @@ -2768,7 +3284,7 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, for (ObjCInterfaceDecl::ivar_iterator IVar = Class->ivar_begin(), IVarEnd = Class->ivar_end(); IVar != IVarEnd; ++IVar) - Results.MaybeAddResult(Result(*IVar, 0), CurContext); + Results.AddResult(Result(*IVar, 0), CurContext, 0, false); } Results.ExitScope(); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 2253f09..0ccb8f2 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -14,6 +14,7 @@ #include "Sema.h" #include "SemaInit.h" #include "Lookup.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -137,6 +138,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, NamedDecl *IIDecl = 0; switch (Result.getResultKind()) { case LookupResult::NotFound: + case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: return 0; @@ -281,6 +283,9 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, else llvm_unreachable("could not have corrected a typo here"); + Diag(Result->getLocation(), diag::note_previous_decl) + << Result->getDeclName(); + SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS); return true; } @@ -555,11 +560,38 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { /// getObjCInterfaceDecl - Look up a for a class declaration in the scope. /// return 0 if one not found. -ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) { +/// +/// \param Id the name of the Objective-C class we're looking for. If +/// typo-correction fixes this name, the Id will be updated +/// to the fixed name. +/// +/// \param RecoverLoc if provided, this routine will attempt to +/// recover from a typo in the name of an existing Objective-C class +/// and, if successful, will return the lookup that results from +/// typo-correction. +ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id, + SourceLocation RecoverLoc) { // The third "scope" argument is 0 since we aren't enabling lazy built-in // creation from this context. NamedDecl *IDecl = LookupSingleName(TUScope, Id, LookupOrdinaryName); + if (!IDecl && !RecoverLoc.isInvalid()) { + // Perform typo correction at the given location, but only if we + // find an Objective-C class name. + LookupResult R(*this, Id, RecoverLoc, LookupOrdinaryName); + if (CorrectTypo(R, TUScope, 0) && + (IDecl = R.getAsSingle())) { + Diag(RecoverLoc, diag::err_undef_interface_suggest) + << Id << IDecl->getDeclName() + << CodeModificationHint::CreateReplacement(RecoverLoc, + IDecl->getNameAsString()); + Diag(IDecl->getLocation(), diag::note_previous_decl) + << IDecl->getDeclName(); + + Id = IDecl->getIdentifier(); + } + } + return dyn_cast_or_null(IDecl); } @@ -773,13 +805,38 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) { if (getLangOptions().Microsoft) return; - // C++ [dcl.typedef]p2: - // In a given non-class scope, a typedef specifier can be used to - // redefine the name of any type declared in that scope to refer - // to the type to which it already refers. if (getLangOptions().CPlusPlus) { + // C++ [dcl.typedef]p2: + // In a given non-class scope, a typedef specifier can be used to + // redefine the name of any type declared in that scope to refer + // to the type to which it already refers. if (!isa(CurContext)) return; + + // C++0x [dcl.typedef]p4: + // In a given class scope, a typedef specifier can be used to redefine + // any class-name declared in that scope that is not also a typedef-name + // to refer to the type to which it already refers. + // + // This wording came in via DR424, which was a correction to the + // wording in DR56, which accidentally banned code like: + // + // struct S { + // typedef struct A { } A; + // }; + // + // in the C++03 standard. We implement the C++0x semantics, which + // allow the above but disallow + // + // struct S { + // typedef int I; + // typedef int I; + // }; + // + // since that was the intent of DR56. + if (!isa(Old)) + return; + Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); @@ -1250,34 +1307,61 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { New->setPreviousDeclaration(Old); } -/// CheckFallThrough - Check that we don't fall off the end of a -/// Statement that should return a value. -/// -/// \returns AlwaysFallThrough iff we always fall off the end of the statement, -/// MaybeFallThrough iff we might or might not fall off the end, -/// NeverFallThroughOrReturn iff we never fall off the end of the statement or -/// return. We assume NeverFallThrough iff we never fall off the end of the -/// statement but we may return. We assume that functions not marked noreturn -/// will return. -Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { - // FIXME: Eventually share this CFG object when we have other warnings based - // of the CFG. This can be done using AnalysisContext. - llvm::OwningPtr cfg (CFG::buildCFG(Root, &Context)); +static void MarkLive(CFGBlock *e, llvm::BitVector &live) { + std::queue workq; + // Prep work queue + workq.push(e); + // Solve + while (!workq.empty()) { + CFGBlock *item = workq.front(); + workq.pop(); + live.set(item->getBlockID()); + for (CFGBlock::succ_iterator I=item->succ_begin(), + E=item->succ_end(); + I != E; + ++I) { + if ((*I) && !live[(*I)->getBlockID()]) { + live.set((*I)->getBlockID()); + workq.push(*I); + } + } + } +} - // FIXME: They should never return 0, fix that, delete this code. - if (cfg == 0) - // FIXME: This should be NeverFallThrough - return NeverFallThroughOrReturn; - // The CFG leaves in dead things, and we don't want to dead code paths to - // confuse us, so we mark all live things first. +static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live, + SourceManager &SM) { std::queue workq; - llvm::BitVector live(cfg->getNumBlockIDs()); // Prep work queue - workq.push(&cfg->getEntry()); + workq.push(e); + SourceLocation top; + if (!e->empty()) + top = e[0][0].getStmt()->getLocStart(); + bool FromMainFile = false; + bool FromSystemHeader = false; + bool TopValid = false; + if (top.isValid()) { + FromMainFile = SM.isFromMainFile(top); + FromSystemHeader = SM.isInSystemHeader(top); + TopValid = true; + } // Solve while (!workq.empty()) { CFGBlock *item = workq.front(); workq.pop(); + SourceLocation c; + if (!item->empty()) + c = item[0][0].getStmt()->getLocStart(); + else if (item->getTerminator()) + c = item->getTerminator()->getLocStart(); + if (c.isValid() + && (!TopValid + || (SM.isFromMainFile(c) && !FromMainFile) + || (FromSystemHeader && !SM.isInSystemHeader(c)) + || SM.isBeforeInTranslationUnit(c, top))) { + top = c; + FromMainFile = SM.isFromMainFile(top); + FromSystemHeader = SM.isInSystemHeader(top); + } live.set(item->getBlockID()); for (CFGBlock::succ_iterator I=item->succ_begin(), E=item->succ_end(); @@ -1289,6 +1373,92 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { } } } + return top; +} + +namespace { +class LineCmp { + SourceManager &SM; +public: + LineCmp(SourceManager &sm) : SM(sm) { + } + bool operator () (SourceLocation l1, SourceLocation l2) { + return l1 < l2; + } +}; +} + +/// CheckUnreachable - Check for unreachable code. +void Sema::CheckUnreachable(AnalysisContext &AC) { + // We avoid checking when there are errors, as the CFG won't faithfully match + // the user's code. + if (getDiagnostics().hasErrorOccurred()) + return; + if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored) + return; + + CFG *cfg = AC.getCFG(); + if (cfg == 0) + return; + + llvm::BitVector live(cfg->getNumBlockIDs()); + // Mark all live things first. + MarkLive(&cfg->getEntry(), live); + + llvm::SmallVector lines; + // First, give warnings for blocks with no predecessors, as they + // can't be part of a loop. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!live[b.getBlockID()]) { + if (b.pred_begin() == b.pred_end()) { + if (!b.empty()) + lines.push_back(b[0].getStmt()->getLocStart()); + else if (b.getTerminator()) + lines.push_back(b.getTerminator()->getLocStart()); + // Avoid excessive errors by marking everything reachable from here + MarkLive(&b, live); + } + } + } + + // And then give warnings for the tops of loops. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!live[b.getBlockID()]) + // Avoid excessive errors by marking everything reachable from here + lines.push_back(MarkLiveTop(&b, live, Context.getSourceManager())); + } + + std::sort(lines.begin(), lines.end(), LineCmp(Context.getSourceManager())); + for (llvm::SmallVector::iterator I = lines.begin(), + E = lines.end(); + I != E; + ++I) + if (I->isValid()) + Diag(*I, diag::warn_unreachable); +} + +/// CheckFallThrough - Check that we don't fall off the end of a +/// Statement that should return a value. +/// +/// \returns AlwaysFallThrough iff we always fall off the end of the statement, +/// MaybeFallThrough iff we might or might not fall off the end, +/// NeverFallThroughOrReturn iff we never fall off the end of the statement or +/// return. We assume NeverFallThrough iff we never fall off the end of the +/// statement but we may return. We assume that functions not marked noreturn +/// will return. +Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) { + CFG *cfg = AC.getCFG(); + if (cfg == 0) + // FIXME: This should be NeverFallThrough + return NeverFallThroughOrReturn; + + // The CFG leaves in dead things, and we don't want to dead code paths to + // confuse us, so we mark all live things first. + std::queue workq; + llvm::BitVector live(cfg->getNumBlockIDs()); + MarkLive(&cfg->getEntry(), live); // Now we know what is live, we check the live precessors of the exit block // and look for fall through paths, being careful to ignore normal returns, @@ -1321,6 +1491,14 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { HasFakeEdge = true; continue; } + if (const AsmStmt *AS = dyn_cast(S)) { + if (AS->isMSAsm()) { + HasFakeEdge = true; + HasLiveReturn = true; + continue; + } + } + bool NoReturnEdge = false; if (CallExpr *C = dyn_cast(S)) { Expr *CEE = C->getCallee()->IgnoreParenCasts(); @@ -1356,7 +1534,8 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { /// function that should return a value. Check that we don't fall off the end /// of a noreturn function. We assume that functions and blocks not marked /// noreturn will return. -void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) { +void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, + AnalysisContext &AC) { // FIXME: Would be nice if we had a better way to control cascading errors, // but for now, avoid them. The problem is that when Parse sees: // int foo() { return a; } @@ -1394,7 +1573,7 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) { return; // FIXME: Function try block if (CompoundStmt *Compound = dyn_cast(Body)) { - switch (CheckFallThrough(Body)) { + switch (CheckFallThrough(AC)) { case MaybeFallThrough: if (HasNoReturn) Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); @@ -1421,7 +1600,8 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) { /// that should return a value. Check that we don't fall off the end of a /// noreturn block. We assume that functions and blocks not marked noreturn /// will return. -void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) { +void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body, + AnalysisContext &AC) { // FIXME: Would be nice if we had a better way to control cascading errors, // but for now, avoid them. The problem is that when Parse sees: // int foo() { return a; } @@ -1447,7 +1627,7 @@ void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) { return; // FIXME: Funtion try block if (CompoundStmt *Compound = dyn_cast(Body)) { - switch (CheckFallThrough(Body)) { + switch (CheckFallThrough(AC)) { case MaybeFallThrough: if (HasNoReturn) Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); @@ -1878,6 +2058,30 @@ DeclarationName Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { Context.getCanonicalType(Ty)); } + case UnqualifiedId::IK_ConstructorTemplateId: { + // In well-formed code, we can only have a constructor + // template-id that refers to the current context, so go there + // to find the actual type being constructed. + CXXRecordDecl *CurClass = dyn_cast(CurContext); + if (!CurClass || CurClass->getIdentifier() != Name.TemplateId->Name) + return DeclarationName(); + + // Determine the type of the class being constructed. + QualType CurClassType; + if (ClassTemplateDecl *ClassTemplate + = CurClass->getDescribedClassTemplate()) + CurClassType = ClassTemplate->getInjectedClassNameType(Context); + else + CurClassType = Context.getTypeDeclType(CurClass); + + // FIXME: Check two things: that the template-id names the same type as + // CurClassType, and that the template-id does not occur when the name + // was qualified. + + return Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(CurClassType)); + } + case UnqualifiedId::IK_DestructorName: { QualType Ty = GetTypeFromParser(Name.DestructorName); if (Ty.isNull()) @@ -3393,7 +3597,12 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, if (NewFD->isOverloadedOperator() && CheckOverloadedOperatorDeclaration(NewFD)) return NewFD->setInvalidDecl(); - + + // Extra checking for C++0x literal operators (C++0x [over.literal]). + if (NewFD->getLiteralIdentifier() && + CheckLiteralOperatorDeclaration(NewFD)) + return NewFD->setInvalidDecl(); + // In C++, check default arguments now that we have merged decls. Unless // the lexical context is the class, because in this case this is done // during delayed parsing anyway. @@ -3717,7 +3926,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { if (getLangOptions().CPlusPlus) { // Make sure we mark the destructor as used if necessary. QualType InitType = VDecl->getType(); - if (const ArrayType *Array = Context.getAsArrayType(InitType)) + while (const ArrayType *Array = Context.getAsArrayType(InitType)) InitType = Context.getBaseElementType(Array); if (InitType->isRecordType()) FinalizeVarWithDestructor(VDecl, InitType); @@ -4267,6 +4476,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, Decl *dcl = D.getAs(); Stmt *Body = BodyArg.takeAs(); + AnalysisContext AC(dcl); FunctionDecl *FD = 0; FunctionTemplateDecl *FunTmpl = dyn_cast_or_null(dcl); if (FunTmpl) @@ -4281,7 +4491,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, // Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3. FD->setHasImplicitReturnZero(true); else - CheckFallThroughForFunctionDef(FD, Body); + CheckFallThroughForFunctionDef(FD, Body, AC); if (!FD->isInvalidDecl()) DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); @@ -4293,7 +4503,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, } else if (ObjCMethodDecl *MD = dyn_cast_or_null(dcl)) { assert(MD == getCurMethodDecl() && "Method parsing confused"); MD->setBody(Body); - CheckFallThroughForFunctionDef(MD, Body); + CheckFallThroughForFunctionDef(MD, Body, AC); MD->setEndLoc(Body->getLocEnd()); if (!MD->isInvalidDecl()) @@ -4351,6 +4561,8 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, if (!Body) return D; + CheckUnreachable(AC); + // Verify that that gotos and switch cases don't jump into scopes illegally. if (CurFunctionNeedsScopeChecking) DiagnoseInvalidJumps(Body); @@ -4657,8 +4869,18 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (Previous.isAmbiguous()) return DeclPtrTy(); - // A tag 'foo::bar' must already exist. if (Previous.empty()) { + // Name lookup did not find anything. However, if the + // nested-name-specifier refers to the current instantiation, + // and that current instantiation has any dependent base + // classes, we might find something at instantiation time: treat + // this as a dependent elaborated-type-specifier. + if (Previous.wasNotFoundInCurrentInstantiation()) { + IsDependent = true; + return DeclPtrTy(); + } + + // A tag 'foo::bar' must already exist. Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange(); Name = 0; Invalid = true; @@ -5054,6 +5276,29 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagD, "Broken injected-class-name"); } +// Traverses the class and any nested classes, making a note of any +// dynamic classes that have no key function so that we can mark all of +// their virtual member functions as "used" at the end of the translation +// unit. This ensures that all functions needed by the vtable will get +// instantiated/synthesized. +static void +RecordDynamicClassesWithNoKeyFunction(Sema &S, CXXRecordDecl *Record, + SourceLocation Loc) { + // We don't look at dependent or undefined classes. + if (Record->isDependentContext() || !Record->isDefinition()) + return; + + if (Record->isDynamicClass() && !S.Context.getKeyFunction(Record)) + S.ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record, Loc)); + + for (DeclContext::decl_iterator D = Record->decls_begin(), + DEnd = Record->decls_end(); + D != DEnd; ++D) { + if (CXXRecordDecl *Nested = dyn_cast(*D)) + RecordDynamicClassesWithNoKeyFunction(S, Nested, Loc); + } +} + void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD, SourceLocation RBraceLoc) { AdjustDeclIfTemplate(TagD); @@ -5066,6 +5311,10 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD, // Exit this scope of this tag's definition. PopDeclContext(); + if (isa(Tag) && !Tag->getDeclContext()->isRecord()) + RecordDynamicClassesWithNoKeyFunction(*this, cast(Tag), + RBraceLoc); + // Notify the consumer that we've defined a tag. Consumer.HandleTagDeclDefinition(Tag); } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 094e5b5..1a12208 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "TargetAttributesSema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" @@ -925,14 +926,19 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) { // If the target wants to validate the section specifier, make it happen. std::string Error = S.Context.Target.isValidSectionSpecifier(SE->getString()); - if (Error.empty()) { - D->addAttr(::new (S.Context) SectionAttr(SE->getString())); + if (!Error.empty()) { + S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target) + << Error; return; } - S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target) - << Error; - + // This attribute cannot be applied to local variables. + if (isa(D) && cast(D)->hasLocalStorage()) { + S.Diag(SE->getLocStart(), diag::err_attribute_section_local_variable); + return; + } + + D->addAttr(::new (S.Context) SectionAttr(SE->getString())); } static void HandleCDeclAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1959,7 +1965,10 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, // Just ignore break; default: - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + // Ask target about the attribute. + const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema(); + if (!TargetAttrs.ProcessDeclAttribute(scope, D, Attr, S)) + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); break; } } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 204d776..a81a04e 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -270,18 +270,18 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { ParmVarDecl *NewParam = New->getParamDecl(p); if (OldParam->hasDefaultArg() && NewParam->hasDefaultArg()) { - // FIXME: If the parameter doesn't have an identifier then the location - // points to the '=' which means that the fixit hint won't remove any - // extra spaces between the type and the '='. - SourceLocation Begin = NewParam->getLocation(); - if (NewParam->getIdentifier()) - Begin = PP.getLocForEndOfToken(Begin); - + // FIXME: If we knew where the '=' was, we could easily provide a fix-it + // hint here. Alternatively, we could walk the type-source information + // for NewParam to find the last source location in the type... but it + // isn't worth the effort right now. This is the kind of test case that + // is hard to get right: + + // int f(int); + // void g(int (*fp)(int) = f); + // void g(int (*fp)(int) = &f); Diag(NewParam->getLocation(), diag::err_param_default_argument_redefinition) - << NewParam->getDefaultArgRange() - << CodeModificationHint::CreateRemoval(SourceRange(Begin, - NewParam->getLocEnd())); + << NewParam->getDefaultArgRange(); // Look for the function declaration where the default argument was // actually written, which may be a declaration prior to Old. @@ -424,6 +424,8 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { /// the innermost class. bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *, const CXXScopeSpec *SS) { + assert(getLangOptions().CPlusPlus && "No class names in C!"); + CXXRecordDecl *CurDecl; if (SS && SS->isSet() && !SS->isInvalid()) { DeclContext *DC = computeDeclContext(*SS, true); @@ -1072,6 +1074,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, << MemberOrBase << true << R.getLookupName() << CodeModificationHint::CreateReplacement(R.getNameLoc(), R.getLookupName().getAsString()); + Diag(Member->getLocation(), diag::note_previous_decl) + << Member->getDeclName(); return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc, LParenLoc, RParenLoc); @@ -1089,7 +1093,14 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, << MemberOrBase << false << R.getLookupName() << CodeModificationHint::CreateReplacement(R.getNameLoc(), R.getLookupName().getAsString()); - + + const CXXBaseSpecifier *BaseSpec = DirectBaseSpec? DirectBaseSpec + : VirtualBaseSpec; + Diag(BaseSpec->getSourceRange().getBegin(), + diag::note_base_class_specified_here) + << BaseSpec->getType() + << BaseSpec->getSourceRange(); + TyD = Type; } } @@ -2054,7 +2065,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { if (!Record->isDependentType()) AddImplicitlyDeclaredMembersToClass(Record); - + if (Record->isInvalidDecl()) return; @@ -2734,18 +2745,23 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { << ClassType << ConvType; } - if (Conversion->getPreviousDeclaration()) { - const NamedDecl *ExpectedPrevDecl = Conversion->getPreviousDeclaration(); + if (Conversion->getPrimaryTemplate()) { + // ignore specializations + } else if (Conversion->getPreviousDeclaration()) { if (FunctionTemplateDecl *ConversionTemplate - = Conversion->getDescribedFunctionTemplate()) - ExpectedPrevDecl = ConversionTemplate->getPreviousDeclaration(); - if (ClassDecl->replaceConversion(ExpectedPrevDecl, Conversion)) + = Conversion->getDescribedFunctionTemplate()) { + if (ClassDecl->replaceConversion( + ConversionTemplate->getPreviousDeclaration(), + ConversionTemplate)) + return DeclPtrTy::make(ConversionTemplate); + } else if (ClassDecl->replaceConversion(Conversion->getPreviousDeclaration(), + Conversion)) return DeclPtrTy::make(Conversion); assert(Conversion->isInvalidDecl() && "Conversion should not get here."); } else if (FunctionTemplateDecl *ConversionTemplate = Conversion->getDescribedFunctionTemplate()) ClassDecl->addConversionFunction(ConversionTemplate); - else if (!Conversion->getPrimaryTemplate()) // ignore specializations + else ClassDecl->addConversionFunction(Conversion); return DeclPtrTy::make(Conversion); @@ -2986,6 +3002,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, break; case UnqualifiedId::IK_ConstructorName: + case UnqualifiedId::IK_ConstructorTemplateId: // C++0x inherited constructors. if (getLangOptions().CPlusPlus0x) break; @@ -4184,7 +4201,7 @@ Sema::PerformInitializationByConstructor(QualType ClassType, else Diag(Loc, diag::err_ovl_no_viable_function_in_init) << ClassType << Range; - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); return 0; case OR_Ambiguous: @@ -4192,7 +4209,7 @@ Sema::PerformInitializationByConstructor(QualType ClassType, Diag(Loc, diag::err_ovl_ambiguous_init) << InitEntity << Range; else Diag(Loc, diag::err_ovl_ambiguous_init) << ClassType << Range; - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs); return 0; case OR_Deleted: @@ -4207,7 +4224,7 @@ Sema::PerformInitializationByConstructor(QualType ClassType, << Best->Function->isDeleted() << RD->getDeclName() << Range; } - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); return 0; } @@ -4373,8 +4390,10 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, = CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase); // Most paths end in a failed conversion. - if (ICS) - ICS->ConversionKind = ImplicitConversionSequence::BadConversion; + if (ICS) { + ICS->setBad(); + ICS->Bad.init(BadConversionSequence::no_conversion, Init, DeclType); + } // C++ [dcl.init.ref]p5: // A reference to type "cv1 T1" is initialized by an expression @@ -4412,7 +4431,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // has a type that is a derived class of the parameter type, // in which case the implicit conversion sequence is a // derived-to-base Conversion (13.3.3.1). - ICS->ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS->setStandard(); ICS->Standard.First = ICK_Identity; ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; ICS->Standard.Third = ICK_Identity; @@ -4497,7 +4516,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // conversion or, if the conversion function returns an // entity of a type that is a derived class of the parameter // type, a derived-to-base Conversion. - ICS->ConversionKind = ImplicitConversionSequence::UserDefinedConversion; + ICS->setUserDefined(); ICS->UserDefined.Before = Best->Conversions[0].Standard; ICS->UserDefined.After = Best->FinalConversion; ICS->UserDefined.ConversionFunction = Best->Function; @@ -4523,15 +4542,16 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, case OR_Ambiguous: if (ICS) { + ICS->setAmbiguous(); for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); Cand != CandidateSet.end(); ++Cand) if (Cand->Viable) - ICS->ConversionFunctionSet.push_back(Cand->Function); + ICS->Ambiguous.addConversion(Cand->Function); break; } Diag(DeclLoc, diag::err_ref_init_ambiguous) << DeclType << Init->getType() << Init->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, &Init, 1); return true; case OR_No_Viable_Function: @@ -4600,7 +4620,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, if (InitLvalue != Expr::LV_Valid && T2->isRecordType() && RefRelationship >= Ref_Compatible_With_Added_Qualification) { if (ICS) { - ICS->ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS->setStandard(); ICS->Standard.First = ICK_Identity; ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; ICS->Standard.Third = ICK_Identity; @@ -4672,30 +4692,27 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, /*InOverloadResolution=*/false); // Of course, that's still a reference binding. - if (ICS->ConversionKind == ImplicitConversionSequence::StandardConversion) { + if (ICS->isStandard()) { ICS->Standard.ReferenceBinding = true; ICS->Standard.RRefBinding = isRValRef; - } else if (ICS->ConversionKind == - ImplicitConversionSequence::UserDefinedConversion) { + } else if (ICS->isUserDefined()) { ICS->UserDefined.After.ReferenceBinding = true; ICS->UserDefined.After.RRefBinding = isRValRef; } - return ICS->ConversionKind == ImplicitConversionSequence::BadConversion; + return ICS->isBad(); } else { ImplicitConversionSequence Conversions; bool badConversion = PerformImplicitConversion(Init, T1, AA_Initializing, false, false, Conversions); if (badConversion) { - if ((Conversions.ConversionKind == - ImplicitConversionSequence::BadConversion) - && !Conversions.ConversionFunctionSet.empty()) { + if (Conversions.isAmbiguous()) { Diag(DeclLoc, diag::err_lvalue_to_rvalue_ambig_ref) << Init->getSourceRange(); - for (int j = Conversions.ConversionFunctionSet.size()-1; + for (int j = Conversions.Ambiguous.conversions().size()-1; j >= 0; j--) { - FunctionDecl *Func = Conversions.ConversionFunctionSet[j]; - Diag(Func->getLocation(), diag::err_ovl_candidate); + FunctionDecl *Func = Conversions.Ambiguous.conversions()[j]; + NoteOverloadCandidate(Func); } } else { @@ -4993,6 +5010,88 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { return false; } +/// CheckLiteralOperatorDeclaration - Check whether the declaration +/// of this literal operator function is well-formed. If so, returns +/// false; otherwise, emits appropriate diagnostics and returns true. +bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { + DeclContext *DC = FnDecl->getDeclContext(); + Decl::Kind Kind = DC->getDeclKind(); + if (Kind != Decl::TranslationUnit && Kind != Decl::Namespace && + Kind != Decl::LinkageSpec) { + Diag(FnDecl->getLocation(), diag::err_literal_operator_outside_namespace) + << FnDecl->getDeclName(); + return true; + } + + bool Valid = false; + + // FIXME: Check for the one valid template signature + // template type operator "" name(); + + if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) { + // Check the first parameter + QualType T = (*Param)->getType(); + + // unsigned long long int and long double are allowed, but only + // alone. + // We also allow any character type; their omission seems to be a bug + // in n3000 + if (Context.hasSameType(T, Context.UnsignedLongLongTy) || + Context.hasSameType(T, Context.LongDoubleTy) || + Context.hasSameType(T, Context.CharTy) || + Context.hasSameType(T, Context.WCharTy) || + Context.hasSameType(T, Context.Char16Ty) || + Context.hasSameType(T, Context.Char32Ty)) { + if (++Param == FnDecl->param_end()) + Valid = true; + goto FinishedParams; + } + + // Otherwise it must be a pointer to const; let's strip those. + const PointerType *PT = T->getAs(); + if (!PT) + goto FinishedParams; + T = PT->getPointeeType(); + if (!T.isConstQualified()) + goto FinishedParams; + T = T.getUnqualifiedType(); + + // Move on to the second parameter; + ++Param; + + // If there is no second parameter, the first must be a const char * + if (Param == FnDecl->param_end()) { + if (Context.hasSameType(T, Context.CharTy)) + Valid = true; + goto FinishedParams; + } + + // const char *, const wchar_t*, const char16_t*, and const char32_t* + // are allowed as the first parameter to a two-parameter function + if (!(Context.hasSameType(T, Context.CharTy) || + Context.hasSameType(T, Context.WCharTy) || + Context.hasSameType(T, Context.Char16Ty) || + Context.hasSameType(T, Context.Char32Ty))) + goto FinishedParams; + + // The second and final parameter must be an std::size_t + T = (*Param)->getType().getUnqualifiedType(); + if (Context.hasSameType(T, Context.getSizeType()) && + ++Param == FnDecl->param_end()) + Valid = true; + } + + // FIXME: This diagnostic is absolutely terrible. +FinishedParams: + if (!Valid) { + Diag(FnDecl->getLocation(), diag::err_literal_operator_params) + << FnDecl->getDeclName(); + return true; + } + + return false; +} + /// ActOnStartLinkageSpecification - Parsed the beginning of a C++ /// linkage specification, including the language and (if present) /// the '{'. ExternLoc is the location of the 'extern', LangLoc is @@ -5693,55 +5792,56 @@ void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc, if (!RD->isDynamicClass()) return; - if (!MD->isOutOfLine()) { - // The only inline functions we care about are constructors. We also defer - // marking the virtual members as referenced until we've reached the end - // of the translation unit. We do this because we need to know the key - // function of the class in order to determine the key function. - if (isa(MD)) - ClassesWithUnmarkedVirtualMembers.insert(std::make_pair(RD, Loc)); + // Ignore declarations that are not definitions. + if (!MD->isThisDeclarationADefinition()) return; - } - const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD); - - if (!KeyFunction) { - // This record does not have a key function, so we assume that the vtable - // will be emitted when it's used by the constructor. - if (!isa(MD)) + if (isa(MD)) { + switch (MD->getParent()->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + // Classes that aren't instantiations of templates don't need their + // virtual methods marked until we see the definition of the key + // function. + return; + + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + // This is a constructor of a class template; mark all of the virtual + // members as referenced to ensure that they get instantiatied. + break; + } + } else if (!MD->isOutOfLine()) { + // Consider only out-of-line definitions of member functions. When we see + // an inline definition, it's too early to compute the key function. + return; + } else if (const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD)) { + // If this is not the key function, we don't need to mark virtual members. + if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) return; - } else if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) { - // We don't have the right key function. + } else { + // The class has no key function, so we've already noted that we need to + // mark the virtual members of this class. return; } - // Mark the members as referenced. - MarkVirtualMembersReferenced(Loc, RD); - ClassesWithUnmarkedVirtualMembers.erase(RD); + // We will need to mark all of the virtual members as referenced to build the + // vtable. + ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(RD, Loc)); } bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() { if (ClassesWithUnmarkedVirtualMembers.empty()) return false; - for (std::map::iterator i = - ClassesWithUnmarkedVirtualMembers.begin(), - e = ClassesWithUnmarkedVirtualMembers.end(); i != e; ++i) { - CXXRecordDecl *RD = i->first; - - const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD); - if (KeyFunction) { - // We know that the class has a key function. If the key function was - // declared in this translation unit, then it the class decl would not - // have been in the ClassesWithUnmarkedVirtualMembers map. - continue; - } - - SourceLocation Loc = i->second; + while (!ClassesWithUnmarkedVirtualMembers.empty()) { + CXXRecordDecl *RD = ClassesWithUnmarkedVirtualMembers.back().first; + SourceLocation Loc = ClassesWithUnmarkedVirtualMembers.back().second; + ClassesWithUnmarkedVirtualMembers.pop_back(); MarkVirtualMembersReferenced(Loc, RD); } - ClassesWithUnmarkedVirtualMembers.clear(); return true; } diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index beadb58..f2fc1f4 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/AST/Expr.h" #include "clang/AST/ASTContext.h" @@ -133,6 +134,19 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, if (SuperName) { // Check if a different kind of symbol declared in this scope. PrevDecl = LookupSingleName(TUScope, SuperName, LookupOrdinaryName); + + if (!PrevDecl) { + // Try to correct for a typo in the superclass name. + LookupResult R(*this, SuperName, SuperLoc, LookupOrdinaryName); + if (CorrectTypo(R, TUScope, 0) && + (PrevDecl = R.getAsSingle())) { + Diag(SuperLoc, diag::err_undef_superclass_suggest) + << SuperName << ClassName << PrevDecl->getDeclName(); + Diag(PrevDecl->getLocation(), diag::note_previous_decl) + << PrevDecl->getDeclName(); + } + } + if (PrevDecl == IDecl) { Diag(SuperLoc, diag::err_recursive_superclass) << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); @@ -317,6 +331,18 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, for (unsigned i = 0; i != NumProtocols; ++i) { ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first); if (!PDecl) { + LookupResult R(*this, ProtocolId[i].first, ProtocolId[i].second, + LookupObjCProtocolName); + if (CorrectTypo(R, TUScope, 0) && + (PDecl = R.getAsSingle())) { + Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest) + << ProtocolId[i].first << R.getLookupName(); + Diag(PDecl->getLocation(), diag::note_previous_decl) + << PDecl->getDeclName(); + } + } + + if (!PDecl) { Diag(ProtocolId[i].second, diag::err_undeclared_protocol) << ProtocolId[i].first; continue; @@ -568,7 +594,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); - ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName); + ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc); /// Check that class of this category is already completely declared. if (!IDecl || IDecl->isForwardDecl()) { CDecl->setInvalidDecl(); @@ -616,7 +642,7 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation( SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc) { - ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName); + ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc); ObjCCategoryDecl *CatIDecl = 0; if (IDecl) { CatIDecl = IDecl->FindCategoryDeclaration(CatName); @@ -667,13 +693,33 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation( if (PrevDecl && !isa(PrevDecl)) { Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName; Diag(PrevDecl->getLocation(), diag::note_previous_definition); - } else { - // Is there an interface declaration of this class; if not, warn! - IDecl = dyn_cast_or_null(PrevDecl); - if (!IDecl || IDecl->isForwardDecl()) { + } else if ((IDecl = dyn_cast_or_null(PrevDecl))) { + // If this is a forward declaration of an interface, warn. + if (IDecl->isForwardDecl()) { Diag(ClassLoc, diag::warn_undef_interface) << ClassName; IDecl = 0; } + } else { + // We did not find anything with the name ClassName; try to correct for + // typos in the class name. + LookupResult R(*this, ClassName, ClassLoc, LookupOrdinaryName); + if (CorrectTypo(R, TUScope, 0) && + (IDecl = R.getAsSingle())) { + // Suggest the (potentially) correct interface name. However, put the + // fix-it hint itself in a separate note, since changing the name in + // the warning would make the fix-it change semantics.However, don't + // provide a code-modification hint or use the typo name for recovery, + // because this is just a warning. The program may actually be correct. + Diag(ClassLoc, diag::warn_undef_interface_suggest) + << ClassName << R.getLookupName(); + Diag(IDecl->getLocation(), diag::note_previous_decl) + << R.getLookupName() + << CodeModificationHint::CreateReplacement(ClassLoc, + R.getLookupName().getAsString()); + IDecl = 0; + } else { + Diag(ClassLoc, diag::warn_undef_interface) << ClassName; + } } // Check that super class name is valid class name @@ -1437,8 +1483,11 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, property->getLocation()); if (SetterMethod) { - if (Context.getCanonicalType(SetterMethod->getResultType()) - != Context.VoidTy) + ObjCPropertyDecl::PropertyAttributeKind CAttr = + property->getPropertyAttributes(); + if ((!(CAttr & ObjCPropertyDecl::OBJC_PR_readonly)) && + Context.getCanonicalType(SetterMethod->getResultType()) != + Context.VoidTy) Diag(SetterMethod->getLocation(), diag::err_setter_type_void); if (SetterMethod->param_size() != 1 || ((*SetterMethod->param_begin())->getType() != property->getType())) { @@ -1563,7 +1612,8 @@ void Sema::CompareMethodParamsInBaseAndSuper(Decl *ClassDecl, // Note: For class/category implemenations, allMethods/allProperties is // always null. -void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, +void Sema::ActOnAtEnd(SourceRange AtEnd, + DeclPtrTy classDecl, DeclPtrTy *allMethods, unsigned allNum, DeclPtrTy *allProperties, unsigned pNum, DeclGroupPtrTy *allTUVars, unsigned tuvNum) { @@ -1580,9 +1630,13 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, || isa(ClassDecl); bool checkIdenticalMethods = isa(ClassDecl); - if (!isInterfaceDeclKind && AtEndLoc.isInvalid()) { - AtEndLoc = ClassDecl->getLocation(); - Diag(AtEndLoc, diag::warn_missing_atend); + if (!isInterfaceDeclKind && AtEnd.isInvalid()) { + // FIXME: This is wrong. We shouldn't be pretending that there is + // an '@end' in the declaration. + SourceLocation L = ClassDecl->getLocation(); + AtEnd.setBegin(L); + AtEnd.setEnd(L); + Diag(L, diag::warn_missing_atend); } DeclContext *DC = dyn_cast(ClassDecl); @@ -1659,17 +1713,17 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, E = CDecl->prop_end(); I != E; ++I) ProcessPropertyDecl(*I, CDecl); - CDecl->setAtEndLoc(AtEndLoc); + CDecl->setAtEndRange(AtEnd); } if (ObjCImplementationDecl *IC=dyn_cast(ClassDecl)) { - IC->setAtEndLoc(AtEndLoc); + IC->setAtEndRange(AtEnd); if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) { ImplMethodsVsClassMethods(IC, IDecl); AtomicPropertySetterGetterRules(IC, IDecl); } } else if (ObjCCategoryImplDecl* CatImplClass = dyn_cast(ClassDecl)) { - CatImplClass->setAtEndLoc(AtEndLoc); + CatImplClass->setAtEndRange(AtEnd); // Find category interface decl and then check that all methods declared // in this interface are implemented in the category @implementation. @@ -1980,6 +2034,32 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, Diag(AtLoc, diag::warn_property_attr_mismatch); Diag(PIDecl->getLocation(), diag::note_property_declare); } + DeclContext *DC = dyn_cast(CCPrimary); + assert(DC && "ClassDecl is not a DeclContext"); + DeclContext::lookup_result Found = + DC->lookup(PIDecl->getDeclName()); + bool PropertyInPrimaryClass = false; + for (; Found.first != Found.second; ++Found.first) + if (isa(*Found.first)) { + PropertyInPrimaryClass = true; + break; + } + if (!PropertyInPrimaryClass) { + // Protocol is not in the primary class. Must build one for it. + ObjCDeclSpec ProtocolPropertyODS; + // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind and + // ObjCPropertyDecl::PropertyAttributeKind have identical values. + // Should consolidate both into one enum type. + ProtocolPropertyODS.setPropertyAttributes( + (ObjCDeclSpec::ObjCPropertyAttributeKind)PIkind); + DeclPtrTy ProtocolPtrTy = + ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS, + PIDecl->getGetterName(), + PIDecl->getSetterName(), + DeclPtrTy::make(CCPrimary), isOverridingProperty, + MethodImplKind); + PIDecl = ProtocolPtrTy.getAs(); + } PIDecl->makeitReadWriteAttribute(); if (Attributes & ObjCDeclSpec::DQ_PR_retain) PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 7bf04d8..034accd 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -14,6 +14,7 @@ #include "Sema.h" #include "SemaInit.h" #include "Lookup.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -565,7 +566,8 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, IsDerivedFrom(ThisType, AnonFieldType)) { // Our base object expression is "this". BaseObjectExpr = new (Context) CXXThisExpr(Loc, - MD->getThisType(Context)); + MD->getThisType(Context), + /*isImplicit=*/true); BaseObjectIsPointer = true; } } else { @@ -943,7 +945,10 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, << SS.getRange() << CodeModificationHint::CreateReplacement(R.getNameLoc(), R.getLookupName().getAsString()); - + if (NamedDecl *ND = R.getAsSingle()) + Diag(ND->getLocation(), diag::note_previous_decl) + << ND->getDeclName(); + // Tell the callee to try to recover. return false; } @@ -1006,11 +1011,18 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // C++ [temp.dep.expr]p3: // An id-expression is type-dependent if it contains: + // -- an identifier that was declared with a dependent type, + // (note: handled after lookup) + // -- a template-id that is dependent, + // (note: handled in BuildTemplateIdExpr) + // -- a conversion-function-id that specifies a dependent type, // -- a nested-name-specifier that contains a class-name that // names a dependent type. // Determine whether this is a member of an unknown specialization; // we need to handle these differently. - if (SS.isSet() && IsDependentIdExpression(*this, SS)) { + if ((Name.getNameKind() == DeclarationName::CXXConversionFunctionName && + Name.getCXXNameType()->isDependentType()) || + (SS.isSet() && IsDependentIdExpression(*this, SS))) { return ActOnDependentIdExpression(SS, Name, NameLoc, isAddressOfOperand, TemplateArgs); @@ -1022,12 +1034,13 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // Just re-use the lookup done by isTemplateName. DecomposeTemplateName(R, Id); } else { - LookupParsedName(R, S, &SS, true); + bool IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl()); + LookupParsedName(R, S, &SS, !IvarLookupFollowUp); // If this reference is in an Objective-C method, then we need to do // some special Objective-C lookup, too. - if (!SS.isSet() && II && getCurMethodDecl()) { - OwningExprResult E(LookupInObjCMethod(R, S, II)); + if (IvarLookupFollowUp) { + OwningExprResult E(LookupInObjCMethod(R, S, II, true)); if (E.isInvalid()) return ExprError(); @@ -1059,6 +1072,16 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, assert(!R.empty() && "DiagnoseEmptyLookup returned false but added no results"); + + // If we found an Objective-C instance variable, let + // LookupInObjCMethod build the appropriate expression to + // reference the ivar. + if (ObjCIvarDecl *Ivar = R.getAsSingle()) { + R.clear(); + OwningExprResult E(LookupInObjCMethod(R, S, Ivar->getIdentifier())); + assert(E.isInvalid() || E.get()); + return move(E); + } } } @@ -1197,7 +1220,8 @@ Sema::BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS, /// Returns a null sentinel to indicate trivial success. Sema::OwningExprResult Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, - IdentifierInfo *II) { + IdentifierInfo *II, + bool AllowBuiltinCreation) { SourceLocation Loc = Lookup.getNameLoc(); // There are two cases to handle here. 1) scoped lookup could have failed, @@ -1278,7 +1302,18 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, T = Context.getObjCClassType(); return Owned(new (Context) ObjCSuperExpr(Loc, T)); } - + if (Lookup.empty() && II && AllowBuiltinCreation) { + // FIXME. Consolidate this with similar code in LookupName. + if (unsigned BuiltinID = II->getBuiltinID()) { + if (!(getLangOptions().CPlusPlus && + Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))) { + NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, + S, Lookup.isForRedeclaration(), + Lookup.getNameLoc()); + if (D) Lookup.addDecl(D); + } + } + } // Sentinel value saying that we didn't do anything special. return Owned((Expr*) 0); } @@ -1353,13 +1388,18 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, QualType ThisType = cast(CurContext)->getThisType(Context); Expr *This = 0; // null signifies implicit access if (IsKnownInstance) { - This = new (Context) CXXThisExpr(SourceLocation(), ThisType); + SourceLocation Loc = R.getNameLoc(); + if (SS.getRange().isValid()) + Loc = SS.getRange().getBegin(); + This = new (Context) CXXThisExpr(Loc, ThisType, /*isImplicit=*/true); } return BuildMemberReferenceExpr(ExprArg(*this, This), ThisType, /*OpLoc*/ SourceLocation(), /*IsArrow*/ true, - SS, R, TemplateArgs); + SS, + /*FirstQualifierInScope*/ 0, + R, TemplateArgs); } bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, @@ -1521,6 +1561,18 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // as they do not get snapshotted. // if (CurBlock && ShouldSnapshotBlockValueReference(CurBlock, VD)) { + if (VD->getType().getTypePtr()->isVariablyModifiedType()) { + Diag(Loc, diag::err_ref_vm_type); + Diag(D->getLocation(), diag::note_declared_at); + return ExprError(); + } + + if (VD->getType()->isArrayType()) { + Diag(Loc, diag::err_ref_array_type); + Diag(D->getLocation(), diag::note_declared_at); + return ExprError(); + } + MarkDeclarationReferenced(Loc, VD); QualType ExprTy = VD->getType().getNonReferenceType(); // The BlocksAttr indicates the variable is bound by-reference. @@ -2252,7 +2304,7 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType, } } - assert(BaseType->isDependentType()); + assert(BaseType->isDependentType() || Name.isDependentName()); // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr // must have pointer type, and the accessed type is the pointee. @@ -2378,6 +2430,9 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, << Name << DC << R.getLookupName() << SS.getRange() << CodeModificationHint::CreateReplacement(R.getNameLoc(), R.getLookupName().getAsString()); + if (NamedDecl *ND = R.getAsSingle()) + SemaRef.Diag(ND->getLocation(), diag::note_previous_decl) + << ND->getDeclName(); return false; } else { R.clear(); @@ -2418,8 +2473,7 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType, } else { OwningExprResult Result = LookupMemberExpr(R, Base, IsArrow, OpLoc, - SS, FirstQualifierInScope, - /*ObjCImpDecl*/ DeclPtrTy()); + SS, /*ObjCImpDecl*/ DeclPtrTy()); if (Result.isInvalid()) { Owned(Base); @@ -2431,13 +2485,15 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType, } return BuildMemberReferenceExpr(ExprArg(*this, Base), BaseType, - OpLoc, IsArrow, SS, R, TemplateArgs); + OpLoc, IsArrow, SS, FirstQualifierInScope, + R, TemplateArgs); } Sema::OwningExprResult Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { Expr *BaseExpr = Base.takeAs(); @@ -2467,11 +2523,17 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, return ExprError(); } - // Diagnose qualified lookups that find only declarations from a - // non-base type. Note that it's okay for lookup to find - // declarations from a non-base type as long as those aren't the - // ones picked by overload resolution. - if (SS.isSet() && CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R)) + // Diagnose lookups that find only declarations from a non-base + // type. This is possible for either qualified lookups (which may + // have been qualified with an unrelated type) or implicit member + // expressions (which were found with unqualified lookup and thus + // may have come from an enclosing scope). Note that it's okay for + // lookup to find declarations from a non-base type as long as those + // aren't the ones picked by overload resolution. + if ((SS.isSet() || !BaseExpr || + (isa(BaseExpr) && + cast(BaseExpr)->isImplicit())) && + CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R)) return ExprError(); // Construct an unresolved result if we in fact got an unresolved @@ -2513,7 +2575,10 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, if (!IsInstanceMember(MemberDecl)) return BuildDeclarationNameExpr(SS, R.getNameLoc(), MemberDecl); - BaseExpr = new (Context) CXXThisExpr(SourceLocation(), BaseExprType); + SourceLocation Loc = R.getNameLoc(); + if (SS.getRange().isValid()) + Loc = SS.getRange().getBegin(); + BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true); } bool ShouldCheckUse = true; @@ -2610,7 +2675,6 @@ Sema::OwningExprResult Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, bool &IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, - NamedDecl *FirstQualifierInScope, DeclPtrTy ObjCImpDecl) { assert(BaseExpr && "no base expression"); @@ -2848,6 +2912,22 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, ObjCInterfaceDecl *ClassDeclared; ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared); + if (!IV) { + // Attempt to correct for typos in ivar names. + LookupResult Res(*this, R.getLookupName(), R.getNameLoc(), + LookupMemberName); + if (CorrectTypo(Res, 0, 0, IDecl) && + (IV = Res.getAsSingle())) { + Diag(R.getNameLoc(), + diag::err_typecheck_member_reference_ivar_suggest) + << IDecl->getDeclName() << MemberName << IV->getDeclName() + << CodeModificationHint::CreateReplacement(R.getNameLoc(), + IV->getNameAsString()); + Diag(IV->getLocation(), diag::note_previous_decl) + << IV->getDeclName(); + } + } + if (IV) { // If the decl being referenced had an error, return an error for this // sub-expr without emitting another error, in order to avoid cascading @@ -3014,6 +3094,24 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType, Setter, MemberLoc, BaseExpr)); } + + // Attempt to correct for typos in property names. + LookupResult Res(*this, R.getLookupName(), R.getNameLoc(), + LookupOrdinaryName); + if (CorrectTypo(Res, 0, 0, IFace, false, OPT) && + Res.getAsSingle()) { + Diag(R.getNameLoc(), diag::err_property_not_found_suggest) + << MemberName << BaseType << Res.getLookupName() + << CodeModificationHint::CreateReplacement(R.getNameLoc(), + Res.getLookupName().getAsString()); + ObjCPropertyDecl *Property = Res.getAsSingle(); + Diag(Property->getLocation(), diag::note_previous_decl) + << Property->getDeclName(); + + return LookupMemberExpr(Res, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl); + } + return ExprError(Diag(MemberLoc, diag::err_property_not_found) << MemberName << BaseType); } @@ -3101,7 +3199,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, Expr *Base = BaseArg.takeAs(); OwningExprResult Result(*this); - if (Base->getType()->isDependentType()) { + if (Base->getType()->isDependentType() || Name.isDependentName()) { Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(), IsArrow, OpLoc, SS, FirstQualifierInScope, @@ -3114,8 +3212,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, DecomposeTemplateName(R, Id); } else { Result = LookupMemberExpr(R, Base, IsArrow, OpLoc, - SS, FirstQualifierInScope, - ObjCImpDecl); + SS, ObjCImpDecl); if (Result.isInvalid()) { Owned(Base); @@ -3136,7 +3233,8 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, } Result = BuildMemberReferenceExpr(ExprArg(*this, Base), Base->getType(), - OpLoc, IsArrow, SS, R, TemplateArgs); + OpLoc, IsArrow, SS, FirstQualifierInScope, + R, TemplateArgs); } return move(Result); @@ -4717,8 +4815,7 @@ QualType Sema::InvalidOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { return QualType(); } -inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, - Expr *&rex) { +QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { // For conversion purposes, we ignore any qualifiers. // For example, "const float" and "float" are equivalent. QualType lhsType = @@ -4779,19 +4876,27 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, return QualType(); } -inline QualType Sema::CheckMultiplyDivideOperands( - Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { +QualType Sema::CheckMultiplyDivideOperands( + Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign, bool isDiv) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorOperands(Loc, lex, rex); QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) - return compType; - return InvalidOperands(Loc, lex, rex); + if (!lex->getType()->isArithmeticType() || + !rex->getType()->isArithmeticType()) + return InvalidOperands(Loc, lex, rex); + + // Check for division by zero. + if (isDiv && + rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) + DiagRuntimeBehavior(Loc, PDiag(diag::warn_division_by_zero) + << rex->getSourceRange()); + + return compType; } -inline QualType Sema::CheckRemainderOperands( +QualType Sema::CheckRemainderOperands( Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) @@ -4801,12 +4906,18 @@ inline QualType Sema::CheckRemainderOperands( QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) - return compType; - return InvalidOperands(Loc, lex, rex); + if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType()) + return InvalidOperands(Loc, lex, rex); + + // Check for remainder by zero. + if (rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) + DiagRuntimeBehavior(Loc, PDiag(diag::warn_remainder_by_zero) + << rex->getSourceRange()); + + return compType; } -inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 +QualType Sema::CheckAdditionOperands( // C99 6.5.6 Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { QualType compType = CheckVectorOperands(Loc, lex, rex); @@ -5072,80 +5183,6 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return LHSTy; } -/// \brief Implements -Wsign-compare. -/// -/// \param lex the left-hand expression -/// \param rex the right-hand expression -/// \param OpLoc the location of the joining operator -/// \param Equality whether this is an "equality-like" join, which -/// suppresses the warning in some cases -void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, - const PartialDiagnostic &PD, bool Equality) { - // Don't warn if we're in an unevaluated context. - if (ExprEvalContexts.back().Context == Unevaluated) - return; - - QualType lt = lex->getType(), rt = rex->getType(); - - // Only warn if both operands are integral. - if (!lt->isIntegerType() || !rt->isIntegerType()) - return; - - // If either expression is value-dependent, don't warn. We'll get another - // chance at instantiation time. - if (lex->isValueDependent() || rex->isValueDependent()) - return; - - // The rule is that the signed operand becomes unsigned, so isolate the - // signed operand. - Expr *signedOperand, *unsignedOperand; - if (lt->isSignedIntegerType()) { - if (rt->isSignedIntegerType()) return; - signedOperand = lex; - unsignedOperand = rex; - } else { - if (!rt->isSignedIntegerType()) return; - signedOperand = rex; - unsignedOperand = lex; - } - - // If the unsigned type is strictly smaller than the signed type, - // then (1) the result type will be signed and (2) the unsigned - // value will fit fully within the signed type, and thus the result - // of the comparison will be exact. - if (Context.getIntWidth(signedOperand->getType()) > - Context.getIntWidth(unsignedOperand->getType())) - return; - - // If the value is a non-negative integer constant, then the - // signed->unsigned conversion won't change it. - llvm::APSInt value; - if (signedOperand->isIntegerConstantExpr(value, Context)) { - assert(value.isSigned() && "result of signed expression not signed"); - - if (value.isNonNegative()) - return; - } - - if (Equality) { - // For (in)equality comparisons, if the unsigned operand is a - // constant which cannot collide with a overflowed signed operand, - // then reinterpreting the signed operand as unsigned will not - // change the result of the comparison. - if (unsignedOperand->isIntegerConstantExpr(value, Context)) { - assert(!value.isSigned() && "result of unsigned expression is signed"); - - // 2's complement: test the top bit. - if (value.isNonNegative()) - return; - } - } - - Diag(OpLoc, PD) - << lex->getType() << rex->getType() - << lex->getSourceRange() << rex->getSourceRange(); -} - // C99 6.5.8, C++ [expr.rel] QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, unsigned OpaqueOpc, bool isRelational) { @@ -5181,7 +5218,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (DeclRefExpr* DRR = dyn_cast(RHSStripped)) if (DRL->getDecl() == DRR->getDecl() && !isa(DRL->getDecl())) - Diag(Loc, diag::warn_selfcomparison); + DiagRuntimeBehavior(Loc, PDiag(diag::warn_selfcomparison)); if (isa(LHSStripped)) LHSStripped = LHSStripped->IgnoreParenCasts(); @@ -5216,15 +5253,17 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, case BinaryOperator::NE: resultComparison = ") != 0"; break; default: assert(false && "Invalid comparison operator"); } - Diag(Loc, diag::warn_stringcompare) - << isa(literalStringStripped) - << literalString->getSourceRange() - << CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ") - << CodeModificationHint::CreateInsertion(lex->getLocStart(), - "strcmp(") - << CodeModificationHint::CreateInsertion( - PP.getLocForEndOfToken(rex->getLocEnd()), - resultComparison); + + DiagRuntimeBehavior(Loc, + PDiag(diag::warn_stringcompare) + << isa(literalStringStripped) + << literalString->getSourceRange() + << CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ") + << CodeModificationHint::CreateInsertion(lex->getLocStart(), + "strcmp(") + << CodeModificationHint::CreateInsertion( + PP.getLocForEndOfToken(rex->getLocEnd()), + resultComparison)); } } @@ -5488,7 +5527,7 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, if (DeclRefExpr* DRL = dyn_cast(lex->IgnoreParens())) if (DeclRefExpr* DRR = dyn_cast(rex->IgnoreParens())) if (DRL->getDecl() == DRR->getDecl()) - Diag(Loc, diag::warn_selfcomparison); + DiagRuntimeBehavior(Loc, PDiag(diag::warn_selfcomparison)); } // Check for comparisons of floating point operands using != and ==. @@ -5776,7 +5815,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, << PointeeTy << Op->getSourceRange(); return QualType(); } - } else if (ResType->isComplexType()) { + } else if (ResType->isAnyComplexType()) { // C99 does not support ++/-- on complex types, we allow as an extension. Diag(OpLoc, diag::ext_integer_increment_complex) << ResType << Op->getSourceRange(); @@ -5877,7 +5916,22 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { NamedDecl *dcl = getPrimaryDecl(op); Expr::isLvalueResult lval = op->isLvalue(Context); - if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) { + MemberExpr *ME = dyn_cast(op); + if (lval == Expr::LV_MemberFunction && ME && + isa(ME->getMemberDecl())) { + ValueDecl *dcl = cast(op)->getMemberDecl(); + // &f where f is a member of the current object, or &o.f, or &p->f + // All these are not allowed, and we need to catch them before the dcl + // branch of the if, below. + Diag(OpLoc, diag::err_unqualified_pointer_member_function) + << dcl; + // FIXME: Improve this diagnostic and provide a fixit. + + // Now recover by acting as if the function had been accessed qualified. + return Context.getMemberPointerType(op->getType(), + Context.getTypeDeclType(cast(dcl->getDeclContext())) + .getTypePtr()); + } else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) { // C99 6.5.3.2p1 // The operand must be either an l-value or a function designator if (!op->getType()->isFunctionType()) { @@ -6065,7 +6119,8 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, break; case BinaryOperator::Mul: case BinaryOperator::Div: - ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc); + ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, false, + Opc == BinaryOperator::Div); break; case BinaryOperator::Rem: ResultTy = CheckRemainderOperands(lhs, rhs, OpLoc); @@ -6101,7 +6156,8 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, break; case BinaryOperator::MulAssign: case BinaryOperator::DivAssign: - CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true); + CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true, + Opc == BinaryOperator::DivAssign); CompLHSTy = CompResultTy; if (!CompResultTy.isNull()) ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); @@ -6155,8 +6211,9 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, /// ParenRange in parentheses. static void SuggestParentheses(Sema &Self, SourceLocation Loc, const PartialDiagnostic &PD, - SourceRange ParenRange) -{ + SourceRange ParenRange, + const PartialDiagnostic &SecondPD = PartialDiagnostic(0), + SourceRange SecondParenRange = SourceRange()) { SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd()); if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { // We can't display the parentheses, so just dig the @@ -6168,6 +6225,21 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc, Self.Diag(Loc, PD) << CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(") << CodeModificationHint::CreateInsertion(EndLoc, ")"); + + if (!SecondPD.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, SecondPD); + return; + } + + Self.Diag(Loc, SecondPD) + << CodeModificationHint::CreateInsertion(SecondParenRange.getBegin(), "(") + << CodeModificationHint::CreateInsertion(EndLoc, ")"); } /// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison @@ -6199,12 +6271,18 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc, PDiag(diag::warn_precedence_bitwise_rel) << SourceRange(lhs->getLocStart(), OpLoc) << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc), + lhs->getSourceRange(), + PDiag(diag::note_precedence_bitwise_first) + << BinOp::getOpcodeStr(Opc), SourceRange(cast(lhs)->getRHS()->getLocStart(), rhs->getLocEnd())); else if (BinOp::isComparisonOp(rhsopc)) SuggestParentheses(Self, OpLoc, PDiag(diag::warn_precedence_bitwise_rel) << SourceRange(OpLoc, rhs->getLocEnd()) << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc), + rhs->getSourceRange(), + PDiag(diag::note_precedence_bitwise_first) + << BinOp::getOpcodeStr(Opc), SourceRange(lhs->getLocEnd(), cast(rhs)->getLHS()->getLocStart())); } @@ -6790,7 +6868,9 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking; BSI->TheDecl->setBody(body.takeAs()); - CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody()); + AnalysisContext AC(BSI->TheDecl); + CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC); + CheckUnreachable(AC); return Owned(new (Context) BlockExpr(BSI->TheDecl, BlockTy, BSI->hasBlockDeclRefExprs)); } @@ -7256,6 +7336,8 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { << E->getSourceRange() << CodeModificationHint::CreateInsertion(Open, "(") << CodeModificationHint::CreateInsertion(Close, ")"); + Diag(Loc, diag::note_condition_assign_to_comparison) + << CodeModificationHint::CreateReplacement(Loc, "=="); } bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) { diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 5f723f9..d10e11f 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -179,7 +179,8 @@ Action::OwningExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) { if (CXXMethodDecl *MD = dyn_cast(CurContext)) if (MD->isInstance()) return Owned(new (Context) CXXThisExpr(ThisLoc, - MD->getThisType(Context))); + MD->getThisType(Context), + /*isImplicit=*/false)); return ExprError(Diag(ThisLoc, diag::err_invalid_this_use)); } @@ -672,20 +673,20 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, case OR_No_Viable_Function: Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) << Name << Range; - PrintOverloadCandidates(Candidates, /*OnlyViable=*/false); + PrintOverloadCandidates(Candidates, OCD_AllCandidates, Args, NumArgs); return true; case OR_Ambiguous: Diag(StartLoc, diag::err_ovl_ambiguous_call) << Name << Range; - PrintOverloadCandidates(Candidates, /*OnlyViable=*/true); + PrintOverloadCandidates(Candidates, OCD_ViableCandidates, Args, NumArgs); return true; case OR_Deleted: Diag(StartLoc, diag::err_ovl_deleted_call) << Best->Function->isDeleted() << Name << Range; - PrintOverloadCandidates(Candidates, /*OnlyViable=*/true); + PrintOverloadCandidates(Candidates, OCD_AllCandidates, Args, NumArgs); return true; } assert(false && "Unreachable, bad result from BestViableFunction"); @@ -921,7 +922,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, << Type << Ex->getSourceRange(); for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) { CXXConversionDecl *Conv = ObjectPtrConversions[i]; - Diag(Conv->getLocation(), diag::err_ovl_candidate); + NoteOverloadCandidate(Conv); } return ExprError(); } @@ -1074,7 +1075,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, AssignmentAction Action, bool AllowExplicit, bool Elidable, ImplicitConversionSequence& ICS) { - ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + ICS.setBad(); + ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); if (Elidable && getLangOptions().CPlusPlus0x) { ICS = TryImplicitConversion(From, ToType, /*SuppressUserConversions=*/false, @@ -1082,7 +1084,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, /*ForceRValue=*/true, /*InOverloadResolution=*/false); } - if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + if (ICS.isBad()) { ICS = TryImplicitConversion(From, ToType, /*SuppressUserConversions=*/false, AllowExplicit, @@ -1092,39 +1094,6 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, return PerformImplicitConversion(From, ToType, ICS, Action); } -/// BuildCXXDerivedToBaseExpr - This routine generates the suitable AST -/// for the derived to base conversion of the expression 'From'. All -/// necessary information is passed in ICS. -bool -Sema::BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind, - const ImplicitConversionSequence& ICS) { - QualType BaseType = - QualType::getFromOpaquePtr(ICS.UserDefined.After.ToTypePtr); - // Must do additional defined to base conversion. - QualType DerivedType = - QualType::getFromOpaquePtr(ICS.UserDefined.After.FromTypePtr); - - From = new (Context) ImplicitCastExpr( - DerivedType.getNonReferenceType(), - CastKind, - From, - DerivedType->isLValueReferenceType()); - From = new (Context) ImplicitCastExpr(BaseType.getNonReferenceType(), - CastExpr::CK_DerivedToBase, From, - BaseType->isLValueReferenceType()); - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); - OwningExprResult FromResult = - BuildCXXConstructExpr( - ICS.UserDefined.After.CopyConstructor->getLocation(), - BaseType, - ICS.UserDefined.After.CopyConstructor, - MultiExprArg(*this, (void **)&From, 1)); - if (FromResult.isInvalid()) - return true; - From = FromResult.takeAs(); - return false; -} - /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType using the pre-computed implicit /// conversion sequence ICS. Returns true if there was an error, false @@ -1135,7 +1104,7 @@ bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const ImplicitConversionSequence &ICS, AssignmentAction Action, bool IgnoreBaseAccess) { - switch (ICS.ConversionKind) { + switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: if (PerformImplicitConversion(From, ToType, ICS.Standard, Action, IgnoreBaseAccess)) @@ -1186,23 +1155,15 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, From = CastArg.takeAs(); - // FIXME: This and the following if statement shouldn't be necessary, but - // there's some nasty stuff involving MaybeBindToTemporary going on here. - if (ICS.UserDefined.After.Second == ICK_Derived_To_Base && - ICS.UserDefined.After.CopyConstructor) { - return BuildCXXDerivedToBaseExpr(From, CastKind, ICS); - } - - if (ICS.UserDefined.After.CopyConstructor) { - From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(), - CastKind, From, - ToType->isLValueReferenceType()); - return false; - } - return PerformImplicitConversion(From, ToType, ICS.UserDefined.After, AA_Converting, IgnoreBaseAccess); } + + case ImplicitConversionSequence::AmbiguousConversion: + DiagnoseAmbiguousConversion(ICS, From->getExprLoc(), + PDiag(diag::err_typecheck_ambiguous_condition) + << From->getSourceRange()); + return true; case ImplicitConversionSequence::EllipsisConversion: assert(false && "Cannot perform an ellipsis conversion"); @@ -1520,14 +1481,18 @@ QualType Sema::CheckPointerToMemberOperands( /// \brief Get the target type of a standard or user-defined conversion. static QualType TargetType(const ImplicitConversionSequence &ICS) { - assert((ICS.ConversionKind == - ImplicitConversionSequence::StandardConversion || - ICS.ConversionKind == - ImplicitConversionSequence::UserDefinedConversion) && - "function only valid for standard or user-defined conversions"); - if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion) - return QualType::getFromOpaquePtr(ICS.Standard.ToTypePtr); - return QualType::getFromOpaquePtr(ICS.UserDefined.After.ToTypePtr); + switch (ICS.getKind()) { + case ImplicitConversionSequence::StandardConversion: + return ICS.Standard.getToType(); + case ImplicitConversionSequence::UserDefinedConversion: + return ICS.UserDefined.After.getToType(); + case ImplicitConversionSequence::AmbiguousConversion: + return ICS.Ambiguous.getToType(); + case ImplicitConversionSequence::EllipsisConversion: + case ImplicitConversionSequence::BadConversion: + llvm_unreachable("function not valid for ellipsis or bad conversions"); + } + return QualType(); // silence warnings } /// \brief Try to convert a type to another according to C++0x 5.16p3. @@ -1557,19 +1522,16 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, /*ForceRValue=*/false, &ICS)) { - assert((ICS.ConversionKind == - ImplicitConversionSequence::StandardConversion || - ICS.ConversionKind == - ImplicitConversionSequence::UserDefinedConversion) && + assert((ICS.isStandard() || ICS.isUserDefined()) && "expected a definite conversion"); bool DirectBinding = - ICS.ConversionKind == ImplicitConversionSequence::StandardConversion ? - ICS.Standard.DirectBinding : ICS.UserDefined.After.DirectBinding; + ICS.isStandard() ? ICS.Standard.DirectBinding + : ICS.UserDefined.After.DirectBinding; if (DirectBinding) return false; } } - ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + ICS.setBad(); // -- If E2 is an rvalue, or if the conversion above cannot be done: // -- if E1 and E2 have class type, and the underlying class types are // the same or one is a base class of the other: @@ -1665,8 +1627,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, /// handles the reference binding specially. static bool ConvertForConditional(Sema &Self, Expr *&E, const ImplicitConversionSequence &ICS) { - if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion && - ICS.Standard.ReferenceBinding) { + if (ICS.isStandard() && ICS.Standard.ReferenceBinding) { assert(ICS.Standard.DirectBinding && "TryClassUnification should never generate indirect ref bindings"); // FIXME: CheckReferenceInit should be able to reuse the ICS instead of @@ -1678,8 +1639,7 @@ static bool ConvertForConditional(Sema &Self, Expr *&E, /*AllowExplicit=*/false, /*ForceRValue=*/false); } - if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion && - ICS.UserDefined.After.ReferenceBinding) { + if (ICS.isUserDefined() && ICS.UserDefined.After.ReferenceBinding) { assert(ICS.UserDefined.After.DirectBinding && "TryClassUnification should never generate indirect ref bindings"); return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType( @@ -1767,10 +1727,8 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (TryClassUnification(*this, RHS, LHS, QuestionLoc, ICSRightToLeft)) return QualType(); - bool HaveL2R = ICSLeftToRight.ConversionKind != - ImplicitConversionSequence::BadConversion; - bool HaveR2L = ICSRightToLeft.ConversionKind != - ImplicitConversionSequence::BadConversion; + bool HaveL2R = !ICSLeftToRight.isBad(); + bool HaveR2L = !ICSRightToLeft.isBad(); // If both can be converted, [...] the program is ill-formed. if (HaveL2R && HaveR2L) { Diag(QuestionLoc, diag::err_conditional_ambiguous) @@ -1837,6 +1795,12 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // type and the other is a null pointer constant; pointer conversions // and qualification conversions are performed to bring them to their // composite pointer type. The result is of the composite pointer type. + // -- The second and third operands have pointer to member type, or one has + // pointer to member type and the other is a null pointer constant; + // pointer to member conversions and qualification conversions are + // performed to bring them to a common type, whose cv-qualification + // shall match the cv-qualification of either the second or the third + // operand. The result is of the common type. QualType Composite = FindCompositePointerType(LHS, RHS); if (!Composite.isNull()) return Composite; @@ -1846,83 +1810,6 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (!Composite.isNull()) return Composite; - // Fourth bullet is same for pointers-to-member. However, the possible - // conversions are far more limited: we have null-to-pointer, upcast of - // containing class, and second-level cv-ness. - // cv-ness is not a union, but must match one of the two operands. (Which, - // frankly, is stupid.) - const MemberPointerType *LMemPtr = LTy->getAs(); - const MemberPointerType *RMemPtr = RTy->getAs(); - if (LMemPtr && - RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(RHS, LTy, CastExpr::CK_NullToMemberPointer); - return LTy; - } - if (RMemPtr && - LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(LHS, RTy, CastExpr::CK_NullToMemberPointer); - return RTy; - } - if (LMemPtr && RMemPtr) { - QualType LPointee = LMemPtr->getPointeeType(); - QualType RPointee = RMemPtr->getPointeeType(); - - QualifierCollector LPQuals, RPQuals; - const Type *LPCan = LPQuals.strip(Context.getCanonicalType(LPointee)); - const Type *RPCan = RPQuals.strip(Context.getCanonicalType(RPointee)); - - // First, we check that the unqualified pointee type is the same. If it's - // not, there's no conversion that will unify the two pointers. - if (LPCan == RPCan) { - - // Second, we take the greater of the two qualifications. If neither - // is greater than the other, the conversion is not possible. - - Qualifiers MergedQuals = LPQuals + RPQuals; - - bool CompatibleQuals = true; - if (MergedQuals.getCVRQualifiers() != LPQuals.getCVRQualifiers() && - MergedQuals.getCVRQualifiers() != RPQuals.getCVRQualifiers()) - CompatibleQuals = false; - else if (LPQuals.getAddressSpace() != RPQuals.getAddressSpace()) - // FIXME: - // C99 6.5.15 as modified by TR 18037: - // If the second and third operands are pointers into different - // address spaces, the address spaces must overlap. - CompatibleQuals = false; - // FIXME: GC qualifiers? - - if (CompatibleQuals) { - // Third, we check if either of the container classes is derived from - // the other. - QualType LContainer(LMemPtr->getClass(), 0); - QualType RContainer(RMemPtr->getClass(), 0); - QualType MoreDerived; - if (Context.getCanonicalType(LContainer) == - Context.getCanonicalType(RContainer)) - MoreDerived = LContainer; - else if (IsDerivedFrom(LContainer, RContainer)) - MoreDerived = LContainer; - else if (IsDerivedFrom(RContainer, LContainer)) - MoreDerived = RContainer; - - if (!MoreDerived.isNull()) { - // The type 'Q Pointee (MoreDerived::*)' is the common type. - // We don't use ImpCastExprToType here because this could still fail - // for ambiguous or inaccessible conversions. - LPointee = Context.getQualifiedType(LPointee, MergedQuals); - QualType Common - = Context.getMemberPointerType(LPointee, MoreDerived.getTypePtr()); - if (PerformImplicitConversion(LHS, Common, Sema::AA_Converting)) - return QualType(); - if (PerformImplicitConversion(RHS, Common, Sema::AA_Converting)) - return QualType(); - return Common; - } - } - } - } - Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange(); @@ -2055,8 +1942,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { /*InOverloadResolution=*/false); ImplicitConversionSequence E1ToC2, E2ToC2; - E1ToC2.ConversionKind = ImplicitConversionSequence::BadConversion; - E2ToC2.ConversionKind = ImplicitConversionSequence::BadConversion; + E1ToC2.setBad(); + E2ToC2.setBad(); if (Context.getCanonicalType(Composite1) != Context.getCanonicalType(Composite2)) { E1ToC2 = TryImplicitConversion(E1, Composite2, @@ -2071,14 +1958,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { /*InOverloadResolution=*/false); } - bool ToC1Viable = E1ToC1.ConversionKind != - ImplicitConversionSequence::BadConversion - && E2ToC1.ConversionKind != - ImplicitConversionSequence::BadConversion; - bool ToC2Viable = E1ToC2.ConversionKind != - ImplicitConversionSequence::BadConversion - && E2ToC2.ConversionKind != - ImplicitConversionSequence::BadConversion; + bool ToC1Viable = !E1ToC1.isBad() && !E2ToC1.isBad(); + bool ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad(); if (ToC1Viable && !ToC2Viable) { if (!PerformImplicitConversion(E1, Composite1, E1ToC1, Sema::AA_Converting) && !PerformImplicitConversion(E2, Composite1, E2ToC1, Sema::AA_Converting)) @@ -2305,71 +2186,3 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { return Owned(FullExpr); } - -/// \brief Determine whether a reference to the given declaration in the -/// current context is an implicit member access -/// (C++ [class.mfct.non-static]p2). -/// -/// FIXME: Should Objective-C also use this approach? -/// -/// \param D the declaration being referenced from the current scope. -/// -/// \param NameLoc the location of the name in the source. -/// -/// \param ThisType if the reference to this declaration is an implicit member -/// access, will be set to the type of the "this" pointer to be used when -/// building that implicit member access. -/// -/// \returns true if this is an implicit member reference (in which case -/// \p ThisType and \p MemberType will be set), or false if it is not an -/// implicit member reference. -bool Sema::isImplicitMemberReference(const LookupResult &R, - QualType &ThisType) { - // If this isn't a C++ method, then it isn't an implicit member reference. - CXXMethodDecl *MD = dyn_cast(CurContext); - if (!MD || MD->isStatic()) - return false; - - // C++ [class.mfct.nonstatic]p2: - // [...] if name lookup (3.4.1) resolves the name in the - // id-expression to a nonstatic nontype member of class X or of - // a base class of X, the id-expression is transformed into a - // class member access expression (5.2.5) using (*this) (9.3.2) - // as the postfix-expression to the left of the '.' operator. - DeclContext *Ctx = 0; - if (R.isUnresolvableResult()) { - // FIXME: this is just picking one at random - Ctx = R.getRepresentativeDecl()->getDeclContext(); - } else if (FieldDecl *FD = R.getAsSingle()) { - Ctx = FD->getDeclContext(); - } else { - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { - CXXMethodDecl *Method = dyn_cast(*I); - FunctionTemplateDecl *FunTmpl = 0; - if (!Method && (FunTmpl = dyn_cast(*I))) - Method = dyn_cast(FunTmpl->getTemplatedDecl()); - - // FIXME: Do we have to know if there are explicit template arguments? - if (Method && !Method->isStatic()) { - Ctx = Method->getParent(); - break; - } - } - } - - if (!Ctx || !Ctx->isRecord()) - return false; - - // Determine whether the declaration(s) we found are actually in a base - // class. If not, this isn't an implicit member reference. - ThisType = MD->getThisType(Context); - - // FIXME: this doesn't really work for overloaded lookups. - - QualType CtxType = Context.getTypeDeclType(cast(Ctx)); - QualType ClassType - = Context.getTypeDeclType(cast(MD->getParent())); - return Context.hasSameType(CtxType, ClassType) || - IsDerivedFrom(ClassType, CtxType); -} - diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 2e31e47..85889fa 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -287,7 +287,8 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr( SourceLocation &receiverNameLoc, SourceLocation &propertyNameLoc) { - ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(&receiverName); + IdentifierInfo *receiverNamePtr = &receiverName; + ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr); // Search for a declared property first. @@ -400,7 +401,7 @@ Sema::ExprResult Sema::ActOnClassMessage( return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName; } } else - ClassDecl = getObjCInterfaceDecl(receiverName); + ClassDecl = getObjCInterfaceDecl(receiverName, receiverLoc); // The following code allows for the following GCC-ism: // diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 3ef5156..1970f56 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -88,7 +88,7 @@ static bool CheckSingleInitializer(Expr *&Init, QualType DeclType, S.Diag(Init->getSourceRange().getBegin(), diag::err_typecheck_convert_ambiguous) << DeclType << Init->getType() << Init->getSourceRange(); - S.PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + S.PrintOverloadCandidates(CandidateSet, Sema::OCD_AllCandidates, &Init, 1); return true; } return false; @@ -670,7 +670,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList, /*ForceRValue=*/false, /*InOverloadResolution=*/false); - if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion) { + if (!ICS.isBad()) { if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS, Sema::AA_Initializing)) hadError = true; @@ -1136,7 +1136,7 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef, // Expand the current designator into the set of replacement // designators, so we have a full subobject path down to where the // member of the anonymous struct/union is actually stored. - DIE->ExpandDesignator(DesigIdx, &Replacements[0], + DIE->ExpandDesignator(SemaRef.Context, DesigIdx, &Replacements[0], &Replacements[0] + Replacements.size()); // Update FieldIter/FieldIndex; @@ -1302,6 +1302,9 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, << FieldName << CurrentObjectType << R.getLookupName() << CodeModificationHint::CreateReplacement(D->getFieldLoc(), R.getLookupName().getAsString()); + SemaRef.Diag(ReplacementField->getLocation(), + diag::note_previous_decl) + << ReplacementField->getDeclName(); } else { SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown) << FieldName << CurrentObjectType; @@ -2224,9 +2227,11 @@ static void TryReferenceInitialization(Sema &S, QualType DestType = Entity.getType(); QualType cv1T1 = DestType->getAs()->getPointeeType(); - QualType T1 = cv1T1.getUnqualifiedType(); + Qualifiers T1Quals; + QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals); QualType cv2T2 = Initializer->getType(); - QualType T2 = cv2T2.getUnqualifiedType(); + Qualifiers T2Quals; + QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals); SourceLocation DeclLoc = Initializer->getLocStart(); // If the initializer is the address of an overloaded function, try @@ -2276,9 +2281,9 @@ static void TryReferenceInitialization(Sema &S, // can occur. This property will be checked by PerformInitialization. if (DerivedToBase) Sequence.AddDerivedToBaseCastStep( - S.Context.getQualifiedType(T1, cv2T2.getQualifiers()), + S.Context.getQualifiedType(T1, T2Quals), /*isLValue=*/true); - if (cv1T1.getQualifiers() != cv2T2.getQualifiers()) + if (T1Quals != T2Quals) Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/true); Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/false); return; @@ -2297,6 +2302,11 @@ static void TryReferenceInitialization(Sema &S, Sequence); if (ConvOvlResult == OR_Success) return; + if (ConvOvlResult != OR_No_Viable_Function) { + Sequence.SetOverloadFailure( + InitializationSequence::FK_ReferenceInitOverloadFailed, + ConvOvlResult); + } } } @@ -2304,7 +2314,7 @@ static void TryReferenceInitialization(Sema &S, // non-volatile const type (i.e., cv1 shall be const), or the reference // shall be an rvalue reference and the initializer expression shall // be an rvalue. - if (!((isLValueRef && cv1T1.getCVRQualifiers() == Qualifiers::Const) || + if (!((isLValueRef && T1Quals.hasConst()) || (isRValueRef && InitLvalue != Expr::LV_Valid))) { if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty()) Sequence.SetOverloadFailure( @@ -2331,9 +2341,9 @@ static void TryReferenceInitialization(Sema &S, RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { if (DerivedToBase) Sequence.AddDerivedToBaseCastStep( - S.Context.getQualifiedType(T1, cv2T2.getQualifiers()), + S.Context.getQualifiedType(T1, T2Quals), /*isLValue=*/false); - if (cv1T1.getQualifiers() != cv2T2.getQualifiers()) + if (T1Quals != T2Quals) Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/false); Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); return; @@ -2381,7 +2391,7 @@ static void TryReferenceInitialization(Sema &S, /*FIXME:InOverloadResolution=*/false, /*UserCast=*/Kind.isExplicitCast()); - if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + if (ICS.isBad()) { // FIXME: Use the conversion function set stored in ICS to turn // this into an overloading ambiguity diagnostic. However, we need // to keep that set as an OverloadCandidateSet rather than as some @@ -2398,8 +2408,10 @@ static void TryReferenceInitialization(Sema &S, // [...] If T1 is reference-related to T2, cv1 must be the // same cv-qualification as, or greater cv-qualification // than, cv2; otherwise, the program is ill-formed. + unsigned T1CVRQuals = T1Quals.getCVRQualifiers(); + unsigned T2CVRQuals = T2Quals.getCVRQualifiers(); if (RefRelationship == Sema::Ref_Related && - !cv1T1.isAtLeastAsQualifiedAs(cv2T2)) { + (T1CVRQuals | T2CVRQuals) != T1CVRQuals) { Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); return; } @@ -2682,14 +2694,14 @@ static void TryUserDefinedConversion(Sema &S, // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; - if (OverloadingResult Result + if (OverloadingResult Result = S.BestViableFunction(CandidateSet, DeclLoc, Best)) { Sequence.SetOverloadFailure( InitializationSequence::FK_UserConversionOverloadFailed, Result); return; } - + FunctionDecl *Function = Best->Function; if (isa(Function)) { @@ -2708,7 +2720,7 @@ static void TryUserDefinedConversion(Sema &S, if (Best->FinalConversion.First || Best->FinalConversion.Second || Best->FinalConversion.Third) { ImplicitConversionSequence ICS; - ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS.setStandard(); ICS.Standard = Best->FinalConversion; Sequence.AddConversionSequenceStep(ICS, DestType); } @@ -2729,7 +2741,7 @@ static void TryImplicitConversion(Sema &S, /*FIXME:InOverloadResolution=*/false, /*UserCast=*/Kind.isExplicitCast()); - if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + if (ICS.isBad()) { Sequence.SetFailed(InitializationSequence::FK_ConversionFailed); return; } @@ -3007,14 +3019,16 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, S.Diag(Loc, diag::err_temp_copy_no_viable) << (int)Entity.getKind() << CurInitExpr->getType() << CurInitExpr->getSourceRange(); - S.PrintOverloadCandidates(CandidateSet, false); + S.PrintOverloadCandidates(CandidateSet, Sema::OCD_AllCandidates, + &CurInitExpr, 1); return S.ExprError(); case OR_Ambiguous: S.Diag(Loc, diag::err_temp_copy_ambiguous) << (int)Entity.getKind() << CurInitExpr->getType() << CurInitExpr->getSourceRange(); - S.PrintOverloadCandidates(CandidateSet, true); + S.PrintOverloadCandidates(CandidateSet, Sema::OCD_ViableCandidates, + &CurInitExpr, 1); return S.ExprError(); case OR_Deleted: @@ -3429,14 +3443,16 @@ bool InitializationSequence::Diagnose(Sema &S, << DestType << Args[0]->getType() << Args[0]->getSourceRange(); - S.PrintOverloadCandidates(FailedCandidateSet, true); + S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_ViableCandidates, + Args, NumArgs); break; case OR_No_Viable_Function: S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition) << Args[0]->getType() << DestType.getNonReferenceType() << Args[0]->getSourceRange(); - S.PrintOverloadCandidates(FailedCandidateSet, false); + S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_AllCandidates, + Args, NumArgs); break; case OR_Deleted: { @@ -3538,13 +3554,15 @@ bool InitializationSequence::Diagnose(Sema &S, case OR_Ambiguous: S.Diag(Kind.getLocation(), diag::err_ovl_ambiguous_init) << DestType << ArgsRange; - S.PrintOverloadCandidates(FailedCandidateSet, true); + S.PrintOverloadCandidates(FailedCandidateSet, + Sema::OCD_ViableCandidates, Args, NumArgs); break; case OR_No_Viable_Function: S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init) << DestType << ArgsRange; - S.PrintOverloadCandidates(FailedCandidateSet, false); + S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_AllCandidates, + Args, NumArgs); break; case OR_Deleted: { diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 1419ceb..cda245d 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -444,10 +444,83 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) { bool Found = false; DeclContext::lookup_const_iterator I, E; - for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) - if (R.isAcceptableDecl(*I)) - R.addDecl(*I), Found = true; + for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) { + if (R.isAcceptableDecl(*I)) { + R.addDecl(*I); + Found = true; + } + } + if (R.getLookupName().getNameKind() + == DeclarationName::CXXConversionFunctionName && + !R.getLookupName().getCXXNameType()->isDependentType() && + isa(DC)) { + // C++ [temp.mem]p6: + // A specialization of a conversion function template is not found by + // name lookup. Instead, any conversion function templates visible in the + // context of the use are considered. [...] + const CXXRecordDecl *Record = cast(DC); + if (!Record->isDefinition()) + return Found; + + const UnresolvedSet *Unresolved = Record->getConversionFunctions(); + for (UnresolvedSet::iterator U = Unresolved->begin(), + UEnd = Unresolved->end(); + U != UEnd; ++U) { + FunctionTemplateDecl *ConvTemplate = dyn_cast(*U); + if (!ConvTemplate) + continue; + + // When we're performing lookup for the purposes of redeclaration, just + // add the conversion function template. When we deduce template + // arguments for specializations, we'll end up unifying the return + // type of the new declaration with the type of the function template. + if (R.isForRedeclaration()) { + R.addDecl(ConvTemplate); + Found = true; + continue; + } + + // C++ [temp.mem]p6: + // [...] For each such operator, if argument deduction succeeds + // (14.9.2.3), the resulting specialization is used as if found by + // name lookup. + // + // When referencing a conversion function for any purpose other than + // a redeclaration (such that we'll be building an expression with the + // result), perform template argument deduction and place the + // specialization into the result set. We do this to avoid forcing all + // callers to perform special deduction for conversion functions. + Sema::TemplateDeductionInfo Info(R.getSema().Context); + FunctionDecl *Specialization = 0; + + const FunctionProtoType *ConvProto + = ConvTemplate->getTemplatedDecl()->getType() + ->getAs(); + assert(ConvProto && "Nonsensical conversion function template type"); + + // Compute the type of the function that we would expect the conversion + // function to have, if it were to match the name given. + // FIXME: Calling convention! + QualType ExpectedType + = R.getSema().Context.getFunctionType( + R.getLookupName().getCXXNameType(), + 0, 0, ConvProto->isVariadic(), + ConvProto->getTypeQuals(), + false, false, 0, 0, + ConvProto->getNoReturnAttr()); + + // Perform template argument deduction against the type that we would + // expect the function to have. + if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType, + Specialization, Info) + == Sema::TDK_Success) { + R.addDecl(Specialization); + Found = true; + } + } + } + return Found; } @@ -550,7 +623,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // example, inside a class without any base classes, we never need to // perform qualified lookup because all of the members are on top of the // identifier chain. - if (LookupQualifiedName(R, Ctx)) + if (LookupQualifiedName(R, Ctx, /*InUnqualifiedLookup=*/true)) return true; } } @@ -577,7 +650,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { for (; S; S = S->getParent()) { DeclContext *Ctx = static_cast(S->getEntity()); - if (Ctx->isTransparentContext()) + if (!Ctx || Ctx->isTransparentContext()) continue; assert(Ctx && Ctx->isFileContext() && @@ -854,11 +927,11 @@ static bool LookupQualifiedNameInUsingDirectives(LookupResult &R, return Found; } -/// @brief Perform qualified name lookup into a given context. +/// \brief Perform qualified name lookup into a given context. /// /// Qualified name lookup (C++ [basic.lookup.qual]) is used to find /// names when the context of those names is explicit specified, e.g., -/// "std::vector" or "x->member". +/// "std::vector" or "x->member", or as part of unqualified name lookup. /// /// Different lookup criteria can find different names. For example, a /// particular scope can have both a struct and a function of the same @@ -866,25 +939,18 @@ static bool LookupQualifiedNameInUsingDirectives(LookupResult &R, /// information about lookup criteria, see the documentation for the /// class LookupCriteria. /// -/// @param LookupCtx The context in which qualified name lookup will +/// \param R captures both the lookup criteria and any lookup results found. +/// +/// \param LookupCtx The context in which qualified name lookup will /// search. If the lookup criteria permits, name lookup may also search /// in the parent contexts or (for C++ classes) base classes. /// -/// @param Name The name of the entity that we are searching for. +/// \param InUnqualifiedLookup true if this is qualified name lookup that +/// occurs as part of unqualified name lookup. /// -/// @param Criteria The criteria that this routine will use to -/// determine which names are visible and which names will be -/// found. Note that name lookup will find a name that is visible by -/// the given criteria, but the entity itself may not be semantically -/// correct or even the kind of entity expected based on the -/// lookup. For example, searching for a nested-name-specifier name -/// might result in an EnumDecl, which is visible but is not permitted -/// as a nested-name-specifier in C++03. -/// -/// @returns The result of name lookup, which includes zero or more -/// declarations and possibly additional information used to diagnose -/// ambiguities. -bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) { +/// \returns true if lookup succeeded, false if it failed. +bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, + bool InUnqualifiedLookup) { assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context"); if (!R.getLookupName()) @@ -922,11 +988,22 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) { // If this isn't a C++ class, we aren't allowed to look into base // classes, we're done. - if (!isa(LookupCtx)) + CXXRecordDecl *LookupRec = dyn_cast(LookupCtx); + if (!LookupRec) return false; + // If we're performing qualified name lookup into a dependent class, + // then we are actually looking into a current instantiation. If we have any + // dependent base classes, then we either have to delay lookup until + // template instantiation time (at which point all bases will be available) + // or we have to fail. + if (!InUnqualifiedLookup && LookupRec->isDependentContext() && + LookupRec->hasAnyDependentBases()) { + R.setNotFoundInCurrentInstantiation(); + return false; + } + // Perform lookup into our base classes. - CXXRecordDecl *LookupRec = cast(LookupCtx); CXXBasePaths Paths; Paths.setOrigin(LookupRec); @@ -1843,6 +1920,9 @@ VisibleDeclsRecord::ShadowMapEntry::end() { } NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { + // Look through using declarations. + ND = ND->getUnderlyingDecl(); + unsigned IDNS = ND->getIdentifierNamespace(); std::list::reverse_iterator SM = ShadowMaps.rbegin(); for (std::list::reverse_iterator SMEnd = ShadowMaps.rend(); @@ -1866,6 +1946,14 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { (*I)->getIdentifierNamespace() != IDNS) continue; + // Functions and function templates in the same scope overload + // rather than hide. FIXME: Look for hiding based on function + // signatures! + if ((*I)->isFunctionOrFunctionTemplate() && + ND->isFunctionOrFunctionTemplate() && + SM == ShadowMaps.rbegin()) + continue; + // We've found a declaration that hides this one. return *I; } @@ -1876,6 +1964,7 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, bool QualifiedNameLookup, + bool InBaseClass, VisibleDeclConsumer &Consumer, VisibleDeclsRecord &Visited) { // Make sure we don't visit the same context twice. @@ -1890,14 +1979,14 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, D != DEnd; ++D) { if (NamedDecl *ND = dyn_cast(*D)) if (Result.isAcceptableDecl(ND)) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND)); + Consumer.FoundDecl(ND, Visited.checkHidden(ND), InBaseClass); Visited.add(ND); } // Visit transparent contexts inside this context. if (DeclContext *InnerCtx = dyn_cast(*D)) { if (InnerCtx->isTransparentContext()) - LookupVisibleDecls(InnerCtx, Result, QualifiedNameLookup, + LookupVisibleDecls(InnerCtx, Result, QualifiedNameLookup, InBaseClass, Consumer, Visited); } } @@ -1909,11 +1998,11 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, DeclContext::udir_iterator I, E; for (llvm::tie(I, E) = Ctx->getUsingDirectives(); I != E; ++I) { LookupVisibleDecls((*I)->getNominatedNamespace(), Result, - QualifiedNameLookup, Consumer, Visited); + QualifiedNameLookup, InBaseClass, Consumer, Visited); } } - // Traverse the contexts of inherited classes. + // Traverse the contexts of inherited C++ classes. if (CXXRecordDecl *Record = dyn_cast(Ctx)) { for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(), BEnd = Record->bases_end(); @@ -1951,11 +2040,49 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, // Find results in this base class (and its bases). ShadowContextRAII Shadow(Visited); LookupVisibleDecls(Record->getDecl(), Result, QualifiedNameLookup, - Consumer, Visited); + true, Consumer, Visited); } } - // FIXME: Look into base classes in Objective-C! + // Traverse the contexts of Objective-C classes. + if (ObjCInterfaceDecl *IFace = dyn_cast(Ctx)) { + // Traverse categories. + for (ObjCCategoryDecl *Category = IFace->getCategoryList(); + Category; Category = Category->getNextClassCategory()) { + ShadowContextRAII Shadow(Visited); + LookupVisibleDecls(Category, Result, QualifiedNameLookup, false, + Consumer, Visited); + } + + // Traverse protocols. + for (ObjCInterfaceDecl::protocol_iterator I = IFace->protocol_begin(), + E = IFace->protocol_end(); I != E; ++I) { + ShadowContextRAII Shadow(Visited); + LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + Visited); + } + + // Traverse the superclass. + if (IFace->getSuperClass()) { + ShadowContextRAII Shadow(Visited); + LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup, + true, Consumer, Visited); + } + } else if (ObjCProtocolDecl *Protocol = dyn_cast(Ctx)) { + for (ObjCProtocolDecl::protocol_iterator I = Protocol->protocol_begin(), + E = Protocol->protocol_end(); I != E; ++I) { + ShadowContextRAII Shadow(Visited); + LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + Visited); + } + } else if (ObjCCategoryDecl *Category = dyn_cast(Ctx)) { + for (ObjCCategoryDecl::protocol_iterator I = Category->protocol_begin(), + E = Category->protocol_end(); I != E; ++I) { + ShadowContextRAII Shadow(Visited); + LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + Visited); + } + } } static void LookupVisibleDecls(Scope *S, LookupResult &Result, @@ -1965,9 +2092,21 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, if (!S) return; + if (!S->getEntity() || !S->getParent() || + ((DeclContext *)S->getEntity())->isFunctionOrMethod()) { + // Walk through the declarations in this Scope. + for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); + D != DEnd; ++D) { + if (NamedDecl *ND = dyn_cast((Decl *)((*D).get()))) + if (Result.isAcceptableDecl(ND)) { + Consumer.FoundDecl(ND, Visited.checkHidden(ND), false); + Visited.add(ND); + } + } + } + DeclContext *Entity = 0; - if (S->getEntity() && - !((DeclContext *)S->getEntity())->isFunctionOrMethod()) { + if (S->getEntity()) { // Look into this scope's declaration context, along with any of its // parent lookup contexts (e.g., enclosing classes), up to the point // where we hit the context stored in the next outer scope. @@ -1976,11 +2115,27 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, for (DeclContext *Ctx = Entity; Ctx && Ctx->getPrimaryContext() != OuterCtx; Ctx = Ctx->getLookupParent()) { + if (ObjCMethodDecl *Method = dyn_cast(Ctx)) { + if (Method->isInstanceMethod()) { + // For instance methods, look for ivars in the method's interface. + LookupResult IvarResult(Result.getSema(), Result.getLookupName(), + Result.getNameLoc(), Sema::LookupMemberName); + ObjCInterfaceDecl *IFace = Method->getClassInterface(); + LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, + /*InBaseClass=*/false, Consumer, Visited); + } + + // We've already performed all of the name lookup that we need + // to for Objective-C methods; the next context will be the + // outer scope. + break; + } + if (Ctx->isFunctionOrMethod()) continue; LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false, - Consumer, Visited); + /*InBaseClass=*/false, Consumer, Visited); } } else if (!S->getParent()) { // Look into the translation unit scope. We walk through the translation @@ -1991,22 +2146,11 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, // doing so would force the normal C++ name-lookup code to look into the // translation unit decl when the IdentifierInfo chains would suffice. // Once we fix that problem (which is part of a more general "don't look - // in DeclContexts unless we have to" optimization), we can eliminate the - // TranslationUnit parameter entirely. + // in DeclContexts unless we have to" optimization), we can eliminate this. Entity = Result.getSema().Context.getTranslationUnitDecl(); LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false, - Consumer, Visited); - } else { - // Walk through the declarations in this Scope. - for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); - D != DEnd; ++D) { - if (NamedDecl *ND = dyn_cast((Decl *)((*D).get()))) - if (Result.isAcceptableDecl(ND)) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND)); - Visited.add(ND); - } - } - } + /*InBaseClass=*/false, Consumer, Visited); + } if (Entity) { // Lookup visible declarations in any namespaces found by using @@ -2015,8 +2159,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(Entity); for (; UI != UEnd; ++UI) LookupVisibleDecls(const_cast(UI->getNominatedNamespace()), - Result, /*QualifiedNameLookup=*/false, Consumer, - Visited); + Result, /*QualifiedNameLookup=*/false, + /*InBaseClass=*/false, Consumer, Visited); } // Lookup names in the parent scope. @@ -2051,8 +2195,8 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); VisibleDeclsRecord Visited; ShadowContextRAII Shadow(Visited); - ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, Consumer, - Visited); + ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, + /*InBaseClass=*/false, Consumer, Visited); } //---------------------------------------------------------------------------- @@ -2075,7 +2219,7 @@ public: explicit TypoCorrectionConsumer(IdentifierInfo *Typo) : Typo(Typo->getName()) { } - virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding); + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass); typedef llvm::SmallVector::const_iterator iterator; iterator begin() const { return BestResults.begin(); } @@ -2087,7 +2231,8 @@ public: } -void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding) { +void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, + bool InBaseClass) { // Don't consider hidden names for typo correction. if (Hiding) return; @@ -2140,11 +2285,19 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding) { /// \param EnteringContext whether we're entering the context described by /// the nested-name-specifier SS. /// +/// \param OPT when non-NULL, the search for visible declarations will +/// also walk the protocols in the qualified interfaces of \p OPT. +/// /// \returns true if the typo was corrected, in which case the \p Res /// structure will contain the results of name lookup for the /// corrected name. Otherwise, returns false. bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, - DeclContext *MemberContext, bool EnteringContext) { + DeclContext *MemberContext, bool EnteringContext, + const ObjCObjectPointerType *OPT) { + + if (Diags.hasFatalErrorOccurred()) + return false; + // We only attempt to correct typos for identifiers. IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo(); if (!Typo) @@ -2161,9 +2314,17 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, return false; TypoCorrectionConsumer Consumer(Typo); - if (MemberContext) + if (MemberContext) { LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer); - else if (SS && SS->isSet()) { + + // Look in qualified interfaces. + if (OPT) { + for (ObjCObjectPointerType::qual_iterator + I = OPT->qual_begin(), E = OPT->qual_end(); + I != E; ++I) + LookupVisibleDecls(*I, Res.getLookupKind(), Consumer); + } + } else if (SS && SS->isSet()) { DeclContext *DC = computeDeclContext(*SS, EnteringContext); if (!DC) return false; @@ -2180,10 +2341,22 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, // have overloads of that name, though). TypoCorrectionConsumer::iterator I = Consumer.begin(); DeclarationName BestName = (*I)->getDeclName(); + + // If we've found an Objective-C ivar or property, don't perform + // name lookup again; we'll just return the result directly. + NamedDecl *FoundBest = 0; + if (isa(*I) || isa(*I)) + FoundBest = *I; ++I; for(TypoCorrectionConsumer::iterator IEnd = Consumer.end(); I != IEnd; ++I) { if (BestName != (*I)->getDeclName()) return false; + + // FIXME: If there are both ivars and properties of the same name, + // don't return both because the callee can't handle two + // results. We really need to separate ivar lookup from property + // lookup to avoid this problem. + FoundBest = 0; } // BestName is the closest viable name to what the user @@ -2198,8 +2371,16 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, // success if we found something that was not ambiguous. Res.clear(); Res.setLookupName(BestName); - if (MemberContext) + + // If we found an ivar or property, add that result; no further + // lookup is required. + if (FoundBest) + Res.addDecl(FoundBest); + // If we're looking into the context of a member, perform qualified + // name lookup on the best name. + else if (MemberContext) LookupQualifiedName(Res, MemberContext); + // Perform lookup as if we had just parsed the best name. else LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, EnteringContext); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 5892081..6ec4d1b 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -145,15 +145,12 @@ ImplicitConversionRank StandardConversionSequence::getRank() const { /// used as part of the ranking of standard conversion sequences /// (C++ 13.3.3.2p4). bool StandardConversionSequence::isPointerConversionToBool() const { - QualType FromType = QualType::getFromOpaquePtr(FromTypePtr); - QualType ToType = QualType::getFromOpaquePtr(ToTypePtr); - // Note that FromType has not necessarily been transformed by the // array-to-pointer or function-to-pointer implicit conversions, so // check for their presence as well as checking whether FromType is // a pointer. - if (ToType->isBooleanType() && - (FromType->isPointerType() || FromType->isBlockPointerType() || + if (getToType()->isBooleanType() && + (getFromType()->isPointerType() || getFromType()->isBlockPointerType() || First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer)) return true; @@ -167,8 +164,8 @@ bool StandardConversionSequence::isPointerConversionToBool() const { bool StandardConversionSequence:: isPointerConversionToVoidPointer(ASTContext& Context) const { - QualType FromType = QualType::getFromOpaquePtr(FromTypePtr); - QualType ToType = QualType::getFromOpaquePtr(ToTypePtr); + QualType FromType = getFromType(); + QualType ToType = getToType(); // Note that FromType has not necessarily been transformed by the // array-to-pointer implicit conversion, so check for its presence @@ -250,6 +247,9 @@ void ImplicitConversionSequence::DebugPrint() const { case EllipsisConversion: fprintf(stderr, "Ellipsis conversion"); break; + case AmbiguousConversion: + fprintf(stderr, "Ambiguous conversion"); + break; case BadConversion: fprintf(stderr, "Bad conversion"); break; @@ -258,6 +258,22 @@ void ImplicitConversionSequence::DebugPrint() const { fprintf(stderr, "\n"); } +void AmbiguousConversionSequence::construct() { + new (&conversions()) ConversionSet(); +} + +void AmbiguousConversionSequence::destruct() { + conversions().~ConversionSet(); +} + +void +AmbiguousConversionSequence::copyFrom(const AmbiguousConversionSequence &O) { + FromTypePtr = O.FromTypePtr; + ToTypePtr = O.ToTypePtr; + new (&conversions()) ConversionSet(O.conversions()); +} + + // IsOverload - Determine whether the given New declaration is an // overload of the declarations in Old. This routine returns false if // New and Old cannot be overloaded, e.g., if New has the same @@ -432,14 +448,14 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, OverloadCandidateSet Conversions; OverloadingResult UserDefResult = OR_Success; if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard)) - ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS.setStandard(); else if (getLangOptions().CPlusPlus && (UserDefResult = IsUserDefinedConversion(From, ToType, ICS.UserDefined, Conversions, !SuppressUserConversions, AllowExplicit, ForceRValue, UserCast)) == OR_Success) { - ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion; + ICS.setUserDefined(); // C++ [over.ics.user]p4: // A conversion of an expression of class type to the same class // type is given Exact Match rank, and a conversion of an @@ -456,10 +472,10 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon))) { // Turn this into a "standard" conversion sequence, so that it // gets ranked with standard conversion sequences. - ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS.setStandard(); ICS.Standard.setAsIdentityConversion(); - ICS.Standard.FromTypePtr = From->getType().getAsOpaquePtr(); - ICS.Standard.ToTypePtr = ToType.getAsOpaquePtr(); + ICS.Standard.setFromType(From->getType()); + ICS.Standard.setToType(ToType); ICS.Standard.CopyConstructor = Constructor; if (ToCanon != FromCanon) ICS.Standard.Second = ICK_Derived_To_Base; @@ -473,17 +489,21 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, // of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or // 13.3.1.6 in all cases, only standard conversion sequences and // ellipsis conversion sequences are allowed. - if (SuppressUserConversions && - ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion) - ICS.ConversionKind = ImplicitConversionSequence::BadConversion; - } else { - ICS.ConversionKind = ImplicitConversionSequence::BadConversion; - if (UserDefResult == OR_Ambiguous) { - for (OverloadCandidateSet::iterator Cand = Conversions.begin(); - Cand != Conversions.end(); ++Cand) - if (Cand->Viable) - ICS.ConversionFunctionSet.push_back(Cand->Function); + if (SuppressUserConversions && ICS.isUserDefined()) { + ICS.setBad(); + ICS.Bad.init(BadConversionSequence::suppressed_user, From, ToType); } + } else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) { + ICS.setAmbiguous(); + ICS.Ambiguous.setFromType(From->getType()); + ICS.Ambiguous.setToType(ToType); + for (OverloadCandidateSet::iterator Cand = Conversions.begin(); + Cand != Conversions.end(); ++Cand) + if (Cand->Viable) + ICS.Ambiguous.addConversion(Cand->Function); + } else { + ICS.setBad(); + ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); } return ICS; @@ -524,7 +544,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, SCS.setAsIdentityConversion(); SCS.Deprecated = false; SCS.IncompatibleObjC = false; - SCS.FromTypePtr = FromType.getAsOpaquePtr(); + SCS.setFromType(FromType); SCS.CopyConstructor = 0; // There are no standard conversions for class types in C++, so @@ -573,7 +593,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // conversion (4.4). (C++ 4.2p2) SCS.Second = ICK_Identity; SCS.Third = ICK_Qualification; - SCS.ToTypePtr = ToType.getAsOpaquePtr(); + SCS.setToType(ToType); return true; } } else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) { @@ -639,7 +659,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, } else if ((FromType->isIntegralType() || FromType->isEnumeralType()) && (ToType->isIntegralType() && !ToType->isEnumeralType())) { // Integral conversions (C++ 4.7). - // FIXME: isIntegralType shouldn't be true for enums in C++. SCS.Second = ICK_Integral_Conversion; FromType = ToType.getUnqualifiedType(); } else if (FromType->isFloatingType() && ToType->isFloatingType()) { @@ -656,7 +675,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, ((FromType->isIntegralType() || FromType->isEnumeralType()) && ToType->isFloatingType())) { // Floating-integral conversions (C++ 4.9). - // FIXME: isIntegralType shouldn't be true for enums in C++. SCS.Second = ICK_Floating_Integral; FromType = ToType.getUnqualifiedType(); } else if ((FromType->isComplexType() && ToType->isArithmeticType()) || @@ -726,7 +744,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, if (CanonFrom != CanonTo) return false; - SCS.ToTypePtr = FromType.getAsOpaquePtr(); + SCS.setToType(FromType); return true; } @@ -1546,8 +1564,7 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, // the argument of the constructor. // QualType ThisType = Constructor->getThisType(Context); - if (Best->Conversions[0].ConversionKind == - ImplicitConversionSequence::EllipsisConversion) + if (Best->Conversions[0].isEllipsis()) User.EllipsisConversion = true; else { User.Before = Best->Conversions[0].Standard; @@ -1555,9 +1572,9 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, } User.ConversionFunction = Constructor; User.After.setAsIdentityConversion(); - User.After.FromTypePtr - = ThisType->getAs()->getPointeeType().getAsOpaquePtr(); - User.After.ToTypePtr = ToType.getAsOpaquePtr(); + User.After.setFromType( + ThisType->getAs()->getPointeeType()); + User.After.setToType(ToType); return OR_Success; } else if (CXXConversionDecl *Conversion = dyn_cast(Best->Function)) { @@ -1617,7 +1634,7 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) { << From->getType() << ToType << From->getSourceRange(); else return false; - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, &From, 1); return true; } @@ -1637,18 +1654,28 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, // conversion sequence than an ellipsis conversion sequence // (13.3.3.1.3). // - if (ICS1.ConversionKind < ICS2.ConversionKind) - return ImplicitConversionSequence::Better; - else if (ICS2.ConversionKind < ICS1.ConversionKind) - return ImplicitConversionSequence::Worse; + // C++0x [over.best.ics]p10: + // For the purpose of ranking implicit conversion sequences as + // described in 13.3.3.2, the ambiguous conversion sequence is + // treated as a user-defined sequence that is indistinguishable + // from any other user-defined conversion sequence. + if (ICS1.getKind() < ICS2.getKind()) { + if (!(ICS1.isUserDefined() && ICS2.isAmbiguous())) + return ImplicitConversionSequence::Better; + } else if (ICS2.getKind() < ICS1.getKind()) { + if (!(ICS2.isUserDefined() && ICS1.isAmbiguous())) + return ImplicitConversionSequence::Worse; + } + + if (ICS1.isAmbiguous() || ICS2.isAmbiguous()) + return ImplicitConversionSequence::Indistinguishable; // Two implicit conversion sequences of the same form are // indistinguishable conversion sequences unless one of the // following rules apply: (C++ 13.3.3.2p3): - if (ICS1.ConversionKind == ImplicitConversionSequence::StandardConversion) + if (ICS1.isStandard()) return CompareStandardConversionSequences(ICS1.Standard, ICS2.Standard); - else if (ICS1.ConversionKind == - ImplicitConversionSequence::UserDefinedConversion) { + else if (ICS1.isUserDefined()) { // User-defined conversion sequence U1 is a better conversion // sequence than another user-defined conversion sequence U2 if // they contain the same user-defined conversion function or @@ -1741,8 +1768,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // Both conversion sequences are conversions to void // pointers. Compare the source types to determine if there's an // inheritance relationship in their sources. - QualType FromType1 = QualType::getFromOpaquePtr(SCS1.FromTypePtr); - QualType FromType2 = QualType::getFromOpaquePtr(SCS2.FromTypePtr); + QualType FromType1 = SCS1.getFromType(); + QualType FromType2 = SCS2.getFromType(); // Adjust the types we're converting from via the array-to-pointer // conversion, if we need to. @@ -1798,8 +1825,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // top-level cv-qualifiers, and the type to which the reference // initialized by S2 refers is more cv-qualified than the type // to which the reference initialized by S1 refers. - QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr); - QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr); + QualType T1 = SCS1.getToType(); + QualType T2 = SCS2.getToType(); T1 = Context.getCanonicalType(T1); T2 = Context.getCanonicalType(T2); Qualifiers T1Quals, T2Quals; @@ -1929,10 +1956,10 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, ImplicitConversionSequence::CompareKind Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, const StandardConversionSequence& SCS2) { - QualType FromType1 = QualType::getFromOpaquePtr(SCS1.FromTypePtr); - QualType ToType1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr); - QualType FromType2 = QualType::getFromOpaquePtr(SCS2.FromTypePtr); - QualType ToType2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr); + QualType FromType1 = SCS1.getFromType(); + QualType ToType1 = SCS1.getToType(); + QualType FromType2 = SCS2.getFromType(); + QualType ToType2 = SCS2.getToType(); // Adjust the types we're converting from via the array-to-pointer // conversion, if we need to. @@ -2105,6 +2132,7 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType, bool InOverloadResolution) { if (ToType->isReferenceType()) { ImplicitConversionSequence ICS; + ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); CheckReferenceInit(From, ToType, /*FIXME:*/From->getLocStart(), SuppressUserConversions, @@ -2163,7 +2191,7 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType, /// parameter of the given member function (@c Method) from the /// expression @p From. ImplicitConversionSequence -Sema::TryObjectArgumentInitialization(QualType FromType, +Sema::TryObjectArgumentInitialization(QualType OrigFromType, CXXMethodDecl *Method, CXXRecordDecl *ActingContext) { QualType ClassType = Context.getTypeDeclType(ActingContext); @@ -2177,9 +2205,10 @@ Sema::TryObjectArgumentInitialization(QualType FromType, // to exit early. ImplicitConversionSequence ICS; ICS.Standard.setAsIdentityConversion(); - ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + ICS.setBad(); // We need to have an object of class type. + QualType FromType = OrigFromType; if (const PointerType *PT = FromType->getAs()) FromType = PT->getPointeeType(); @@ -2199,8 +2228,11 @@ Sema::TryObjectArgumentInitialization(QualType FromType, QualType FromTypeCanon = Context.getCanonicalType(FromType); if (ImplicitParamType.getCVRQualifiers() != FromTypeCanon.getLocalCVRQualifiers() && - !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) + !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) { + ICS.Bad.init(BadConversionSequence::bad_qualifiers, + OrigFromType, ImplicitParamType); return ICS; + } // Check that we have either the same type or a derived type. It // affects the conversion rank. @@ -2209,13 +2241,15 @@ Sema::TryObjectArgumentInitialization(QualType FromType, ICS.Standard.Second = ICK_Identity; else if (IsDerivedFrom(FromType, ClassType)) ICS.Standard.Second = ICK_Derived_To_Base; - else + else { + ICS.Bad.init(BadConversionSequence::unrelated_class, FromType, ImplicitParamType); return ICS; + } // Success. Mark this as a reference binding. - ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; - ICS.Standard.FromTypePtr = FromType.getAsOpaquePtr(); - ICS.Standard.ToTypePtr = ImplicitParamType.getAsOpaquePtr(); + ICS.setStandard(); + ICS.Standard.setFromType(FromType); + ICS.Standard.setToType(ImplicitParamType); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; ICS.Standard.RRefBinding = false; @@ -2244,7 +2278,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) { ImplicitConversionSequence ICS = TryObjectArgumentInitialization(From->getType(), Method, Method->getParent()); - if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) + if (ICS.isBad()) return Diag(From->getSourceRange().getBegin(), diag::err_implicit_object_parameter_init) << ImplicitParamRecordType << FromRecordType << From->getSourceRange(); @@ -2276,8 +2310,8 @@ ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) { /// of the expression From to bool (C++0x [conv]p3). bool Sema::PerformContextuallyConvertToBool(Expr *&From) { ImplicitConversionSequence ICS = TryContextuallyConvertToBool(From); - if (!PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting)) - return false; + if (!ICS.isBad()) + return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting); if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy)) return Diag(From->getSourceRange().getBegin(), @@ -2307,8 +2341,6 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, const FunctionProtoType* Proto = dyn_cast(Function->getType()->getAs()); assert(Proto && "Functions without a prototype cannot be overloaded"); - assert(!isa(Function) && - "Use AddConversionCandidate for conversion functions"); assert(!Function->getDescribedFunctionTemplate() && "Use AddTemplateOverloadCandidate for function templates"); @@ -2363,6 +2395,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, if ((NumArgs + (PartialOverloading && NumArgs)) > NumArgsInProto && !Proto->isVariadic()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_many_arguments; return; } @@ -2375,6 +2408,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, if (NumArgs < MinRequiredArgs && !PartialOverloading) { // Not enough arguments. Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_few_arguments; return; } @@ -2392,35 +2426,16 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, = TryCopyInitialization(Args[ArgIdx], ParamType, SuppressUserConversions, ForceRValue, /*InOverloadResolution=*/true); - if (Candidate.Conversions[ArgIdx].ConversionKind - == ImplicitConversionSequence::BadConversion) { - // 13.3.3.1-p10 If several different sequences of conversions exist that - // each convert the argument to the parameter type, the implicit conversion - // sequence associated with the parameter is defined to be the unique conversion - // sequence designated the ambiguous conversion sequence. For the purpose of - // ranking implicit conversion sequences as described in 13.3.3.2, the ambiguous - // conversion sequence is treated as a user-defined sequence that is - // indistinguishable from any other user-defined conversion sequence - if (!Candidate.Conversions[ArgIdx].ConversionFunctionSet.empty()) { - Candidate.Conversions[ArgIdx].ConversionKind = - ImplicitConversionSequence::UserDefinedConversion; - // Set the conversion function to one of them. As due to ambiguity, - // they carry the same weight and is needed for overload resolution - // later. - Candidate.Conversions[ArgIdx].UserDefined.ConversionFunction = - Candidate.Conversions[ArgIdx].ConversionFunctionSet[0]; - } - else { - Candidate.Viable = false; - break; - } + if (Candidate.Conversions[ArgIdx].isBad()) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; + break; } } else { // (C++ 13.3.2p2): For the purposes of overload resolution, any // argument for which there is no corresponding parameter is // considered to ""match the ellipsis" (C+ 13.3.3.1.3). - Candidate.Conversions[ArgIdx].ConversionKind - = ImplicitConversionSequence::EllipsisConversion; + Candidate.Conversions[ArgIdx].setEllipsis(); } } } @@ -2470,8 +2485,6 @@ void Sema::AddMethodCandidate(NamedDecl *Decl, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, bool ForceRValue) { - - // FIXME: use this CXXRecordDecl *ActingContext = cast(Decl->getDeclContext()); if (isa(Decl)) @@ -2509,8 +2522,6 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, const FunctionProtoType* Proto = dyn_cast(Method->getType()->getAs()); assert(Proto && "Methods without a prototype cannot be overloaded"); - assert(!isa(Method) && - "Use AddConversionCandidate for conversion functions"); assert(!isa(Method) && "Use AddOverloadCandidate for constructors"); @@ -2534,6 +2545,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, // list (8.3.5). if (NumArgs > NumArgsInProto && !Proto->isVariadic()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_many_arguments; return; } @@ -2546,6 +2558,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, if (NumArgs < MinRequiredArgs) { // Not enough arguments. Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_few_arguments; return; } @@ -2560,9 +2573,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, // parameter. Candidate.Conversions[0] = TryObjectArgumentInitialization(ObjectType, Method, ActingContext); - if (Candidate.Conversions[0].ConversionKind - == ImplicitConversionSequence::BadConversion) { + if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; return; } } @@ -2580,17 +2593,16 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, = TryCopyInitialization(Args[ArgIdx], ParamType, SuppressUserConversions, ForceRValue, /*InOverloadResolution=*/true); - if (Candidate.Conversions[ArgIdx + 1].ConversionKind - == ImplicitConversionSequence::BadConversion) { + if (Candidate.Conversions[ArgIdx + 1].isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; break; } } else { // (C++ 13.3.2p2): For the purposes of overload resolution, any // argument for which there is no corresponding parameter is // considered to ""match the ellipsis" (C+ 13.3.3.1.3). - Candidate.Conversions[ArgIdx + 1].ConversionKind - = ImplicitConversionSequence::EllipsisConversion; + Candidate.Conversions[ArgIdx + 1].setEllipsis(); } } } @@ -2675,6 +2687,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, OverloadCandidate &Candidate = CandidateSet.back(); Candidate.Function = FunctionTemplate->getTemplatedDecl(); Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; return; @@ -2714,9 +2727,8 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.FinalConversion.setAsIdentityConversion(); - Candidate.FinalConversion.FromTypePtr - = Conversion->getConversionType().getAsOpaquePtr(); - Candidate.FinalConversion.ToTypePtr = ToType.getAsOpaquePtr(); + Candidate.FinalConversion.setFromType(Conversion->getConversionType()); + Candidate.FinalConversion.setToType(ToType); // Determine the implicit conversion sequence for the implicit // object parameter. @@ -2730,9 +2742,9 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, // in overload resolution. if (Candidate.Conversions[0].Standard.Second == ICK_Derived_To_Base) Candidate.Conversions[0].Standard.Second = ICK_Identity; - if (Candidate.Conversions[0].ConversionKind - == ImplicitConversionSequence::BadConversion) { + if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; return; } @@ -2744,6 +2756,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType(); if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; return; } @@ -2774,13 +2787,14 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, /*ForceRValue=*/false, /*InOverloadResolution=*/false); - switch (ICS.ConversionKind) { + switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: Candidate.FinalConversion = ICS.Standard; break; case ImplicitConversionSequence::BadConversion: Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; break; default: @@ -2852,16 +2866,16 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // object parameter. ImplicitConversionSequence ObjectInit = TryObjectArgumentInitialization(ObjectType, Conversion, ActingContext); - if (ObjectInit.ConversionKind == ImplicitConversionSequence::BadConversion) { + if (ObjectInit.isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; return; } // The first conversion is actually a user-defined conversion whose // first conversion is ObjectInit's standard conversion (which is // effectively a reference binding). Record it as such. - Candidate.Conversions[0].ConversionKind - = ImplicitConversionSequence::UserDefinedConversion; + Candidate.Conversions[0].setUserDefined(); Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard; Candidate.Conversions[0].UserDefined.EllipsisConversion = false; Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion; @@ -2877,6 +2891,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // list (8.3.5). if (NumArgs > NumArgsInProto && !Proto->isVariadic()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_many_arguments; return; } @@ -2885,6 +2900,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, if (NumArgs < NumArgsInProto) { // Not enough arguments. Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_few_arguments; return; } @@ -2902,17 +2918,16 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, /*SuppressUserConversions=*/false, /*ForceRValue=*/false, /*InOverloadResolution=*/false); - if (Candidate.Conversions[ArgIdx + 1].ConversionKind - == ImplicitConversionSequence::BadConversion) { + if (Candidate.Conversions[ArgIdx + 1].isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; break; } } else { // (C++ 13.3.2p2): For the purposes of overload resolution, any // argument for which there is no corresponding parameter is // considered to ""match the ellipsis" (C+ 13.3.3.1.3). - Candidate.Conversions[ArgIdx + 1].ConversionKind - = ImplicitConversionSequence::EllipsisConversion; + Candidate.Conversions[ArgIdx + 1].setEllipsis(); } } } @@ -3046,9 +3061,9 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, /*ForceRValue=*/false, /*InOverloadResolution=*/false); } - if (Candidate.Conversions[ArgIdx].ConversionKind - == ImplicitConversionSequence::BadConversion) { + if (Candidate.Conversions[ArgIdx].isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; break; } } @@ -4274,130 +4289,386 @@ OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, return OR_Success; } +namespace { + +enum OverloadCandidateKind { + oc_function, + oc_method, + oc_constructor, + oc_function_template, + oc_method_template, + oc_constructor_template, + oc_implicit_default_constructor, + oc_implicit_copy_constructor, + oc_implicit_copy_assignment +}; + +OverloadCandidateKind ClassifyOverloadCandidate(Sema &S, + FunctionDecl *Fn, + std::string &Description) { + bool isTemplate = false; + + if (FunctionTemplateDecl *FunTmpl = Fn->getPrimaryTemplate()) { + isTemplate = true; + Description = S.getTemplateArgumentBindingsText( + FunTmpl->getTemplateParameters(), *Fn->getTemplateSpecializationArgs()); + } + + if (CXXConstructorDecl *Ctor = dyn_cast(Fn)) { + if (!Ctor->isImplicit()) + return isTemplate ? oc_constructor_template : oc_constructor; + + return Ctor->isCopyConstructor() ? oc_implicit_copy_constructor + : oc_implicit_default_constructor; + } + + if (CXXMethodDecl *Meth = dyn_cast(Fn)) { + // This actually gets spelled 'candidate function' for now, but + // it doesn't hurt to split it out. + if (!Meth->isImplicit()) + return isTemplate ? oc_method_template : oc_method; + + assert(Meth->isCopyAssignment() + && "implicit method is not copy assignment operator?"); + return oc_implicit_copy_assignment; + } + + return isTemplate ? oc_function_template : oc_function; +} + +} // end anonymous namespace + +// Notes the location of an overload candidate. +void Sema::NoteOverloadCandidate(FunctionDecl *Fn) { + std::string FnDesc; + OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Fn, FnDesc); + Diag(Fn->getLocation(), diag::note_ovl_candidate) + << (unsigned) K << FnDesc; +} + +/// Diagnoses an ambiguous conversion. The partial diagnostic is the +/// "lead" diagnostic; it will be given two arguments, the source and +/// target types of the conversion. +void Sema::DiagnoseAmbiguousConversion(const ImplicitConversionSequence &ICS, + SourceLocation CaretLoc, + const PartialDiagnostic &PDiag) { + Diag(CaretLoc, PDiag) + << ICS.Ambiguous.getFromType() << ICS.Ambiguous.getToType(); + for (AmbiguousConversionSequence::const_iterator + I = ICS.Ambiguous.begin(), E = ICS.Ambiguous.end(); I != E; ++I) { + NoteOverloadCandidate(*I); + } +} + +namespace { + +void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { + const ImplicitConversionSequence &Conv = Cand->Conversions[I]; + assert(Conv.isBad()); + assert(Cand->Function && "for now, candidate must be a function"); + FunctionDecl *Fn = Cand->Function; + + // There's a conversion slot for the object argument if this is a + // non-constructor method. Note that 'I' corresponds the + // conversion-slot index. + bool isObjectArgument = false; + if (isa(Fn) && !isa(Fn)) { + if (I == 0) + isObjectArgument = true; + else + I--; + } + + std::string FnDesc; + OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc); + + Expr *FromExpr = Conv.Bad.FromExpr; + QualType FromTy = Conv.Bad.getFromType(); + QualType ToTy = Conv.Bad.getToType(); + + // Do some hand-waving analysis to see if the non-viability is due to a + CanQualType CFromTy = S.Context.getCanonicalType(FromTy); + CanQualType CToTy = S.Context.getCanonicalType(ToTy); + if (CanQual RT = CToTy->getAs()) + CToTy = RT->getPointeeType(); + else { + // TODO: detect and diagnose the full richness of const mismatches. + if (CanQual FromPT = CFromTy->getAs()) + if (CanQual ToPT = CToTy->getAs()) + CFromTy = FromPT->getPointeeType(), CToTy = ToPT->getPointeeType(); + } + + if (CToTy.getUnqualifiedType() == CFromTy.getUnqualifiedType() && + !CToTy.isAtLeastAsQualifiedAs(CFromTy)) { + // It is dumb that we have to do this here. + while (isa(CFromTy)) + CFromTy = CFromTy->getAs()->getElementType(); + while (isa(CToTy)) + CToTy = CFromTy->getAs()->getElementType(); + + Qualifiers FromQs = CFromTy.getQualifiers(); + Qualifiers ToQs = CToTy.getQualifiers(); + + if (FromQs.getAddressSpace() != ToQs.getAddressSpace()) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy + << FromQs.getAddressSpace() << ToQs.getAddressSpace() + << (unsigned) isObjectArgument << I+1; + return; + } + + unsigned CVR = FromQs.getCVRQualifiers() & ~ToQs.getCVRQualifiers(); + assert(CVR && "unexpected qualifiers mismatch"); + + if (isObjectArgument) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr_this) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << (CVR - 1); + } else { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << (CVR - 1) << I+1; + } + return; + } + + // TODO: specialize more based on the kind of mismatch + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << ToTy << (unsigned) isObjectArgument << I+1; +} + +void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, + unsigned NumFormalArgs) { + // TODO: treat calls to a missing default constructor as a special case + + FunctionDecl *Fn = Cand->Function; + const FunctionProtoType *FnTy = Fn->getType()->getAs(); + + unsigned MinParams = Fn->getMinRequiredArguments(); + + // at least / at most / exactly + unsigned mode, modeCount; + if (NumFormalArgs < MinParams) { + assert(Cand->FailureKind == ovl_fail_too_few_arguments); + if (MinParams != FnTy->getNumArgs() || FnTy->isVariadic()) + mode = 0; // "at least" + else + mode = 2; // "exactly" + modeCount = MinParams; + } else { + assert(Cand->FailureKind == ovl_fail_too_many_arguments); + if (MinParams != FnTy->getNumArgs()) + mode = 1; // "at most" + else + mode = 2; // "exactly" + modeCount = FnTy->getNumArgs(); + } + + std::string Description; + OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description); + + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity) + << (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs; +} + +void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, + Expr **Args, unsigned NumArgs) { + FunctionDecl *Fn = Cand->Function; + + // Note deleted candidates, but only if they're viable. + if (Cand->Viable && (Fn->isDeleted() || Fn->hasAttr())) { + std::string FnDesc; + OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc); + + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted) + << FnKind << FnDesc << Fn->isDeleted(); + return; + } + + // We don't really have anything else to say about viable candidates. + if (Cand->Viable) { + S.NoteOverloadCandidate(Fn); + return; + } + + switch (Cand->FailureKind) { + case ovl_fail_too_many_arguments: + case ovl_fail_too_few_arguments: + return DiagnoseArityMismatch(S, Cand, NumArgs); + + case ovl_fail_bad_deduction: + return S.NoteOverloadCandidate(Fn); + + case ovl_fail_bad_conversion: + for (unsigned I = 0, N = Cand->Conversions.size(); I != N; ++I) + if (Cand->Conversions[I].isBad()) + return DiagnoseBadConversion(S, Cand, I); + + // FIXME: this currently happens when we're called from SemaInit + // when user-conversion overload fails. Figure out how to handle + // those conditions and diagnose them well. + return S.NoteOverloadCandidate(Fn); + } +} + +void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) { + // Desugar the type of the surrogate down to a function type, + // retaining as many typedefs as possible while still showing + // the function type (and, therefore, its parameter types). + QualType FnType = Cand->Surrogate->getConversionType(); + bool isLValueReference = false; + bool isRValueReference = false; + bool isPointer = false; + if (const LValueReferenceType *FnTypeRef = + FnType->getAs()) { + FnType = FnTypeRef->getPointeeType(); + isLValueReference = true; + } else if (const RValueReferenceType *FnTypeRef = + FnType->getAs()) { + FnType = FnTypeRef->getPointeeType(); + isRValueReference = true; + } + if (const PointerType *FnTypePtr = FnType->getAs()) { + FnType = FnTypePtr->getPointeeType(); + isPointer = true; + } + // Desugar down to a function type. + FnType = QualType(FnType->getAs(), 0); + // Reconstruct the pointer/reference as appropriate. + if (isPointer) FnType = S.Context.getPointerType(FnType); + if (isRValueReference) FnType = S.Context.getRValueReferenceType(FnType); + if (isLValueReference) FnType = S.Context.getLValueReferenceType(FnType); + + S.Diag(Cand->Surrogate->getLocation(), diag::note_ovl_surrogate_cand) + << FnType; +} + +void NoteBuiltinOperatorCandidate(Sema &S, + const char *Opc, + SourceLocation OpLoc, + OverloadCandidate *Cand) { + assert(Cand->Conversions.size() <= 2 && "builtin operator is not binary"); + std::string TypeStr("operator"); + TypeStr += Opc; + TypeStr += "("; + TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString(); + if (Cand->Conversions.size() == 1) { + TypeStr += ")"; + S.Diag(OpLoc, diag::note_ovl_builtin_unary_candidate) << TypeStr; + } else { + TypeStr += ", "; + TypeStr += Cand->BuiltinTypes.ParamTypes[1].getAsString(); + TypeStr += ")"; + S.Diag(OpLoc, diag::note_ovl_builtin_binary_candidate) << TypeStr; + } +} + +void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc, + OverloadCandidate *Cand) { + unsigned NoOperands = Cand->Conversions.size(); + for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) { + const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx]; + if (ICS.isBad()) break; // all meaningless after first invalid + if (!ICS.isAmbiguous()) continue; + + S.DiagnoseAmbiguousConversion(ICS, OpLoc, + PDiag(diag::note_ambiguous_type_conversion)); + } +} + +struct CompareOverloadCandidatesForDisplay { + Sema &S; + CompareOverloadCandidatesForDisplay(Sema &S) : S(S) {} + + bool operator()(const OverloadCandidate *L, + const OverloadCandidate *R) { + // Order first by viability. + if (L->Viable) { + if (!R->Viable) return true; + + // TODO: introduce a tri-valued comparison for overload + // candidates. Would be more worthwhile if we had a sort + // that could exploit it. + if (S.isBetterOverloadCandidate(*L, *R)) return true; + if (S.isBetterOverloadCandidate(*R, *L)) return false; + } else if (R->Viable) + return false; + + // Put declared functions first. + if (L->Function) { + if (!R->Function) return true; + return S.SourceMgr.isBeforeInTranslationUnit(L->Function->getLocation(), + R->Function->getLocation()); + } else if (R->Function) return false; + + // Then surrogates. + if (L->IsSurrogate) { + if (!R->IsSurrogate) return true; + return S.SourceMgr.isBeforeInTranslationUnit(L->Surrogate->getLocation(), + R->Surrogate->getLocation()); + } else if (R->IsSurrogate) return false; + + // And builtins just come in a jumble. + return false; + } +}; + +} // end anonymous namespace + /// PrintOverloadCandidates - When overload resolution fails, prints /// diagnostic messages containing the candidates in the candidate -/// set. If OnlyViable is true, only viable candidates will be printed. +/// set. void Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, - bool OnlyViable, + OverloadCandidateDisplayKind OCD, + Expr **Args, unsigned NumArgs, const char *Opc, SourceLocation OpLoc) { - OverloadCandidateSet::iterator Cand = CandidateSet.begin(), - LastCand = CandidateSet.end(); - bool Reported = false; - for (; Cand != LastCand; ++Cand) { - if (Cand->Viable || !OnlyViable) { - if (Cand->Function) { - if (Cand->Function->isDeleted() || - Cand->Function->getAttr()) { - // Deleted or "unavailable" function. - Diag(Cand->Function->getLocation(), diag::err_ovl_candidate_deleted) - << Cand->Function->isDeleted(); - } else if (FunctionTemplateDecl *FunTmpl - = Cand->Function->getPrimaryTemplate()) { - // Function template specialization - // FIXME: Give a better reason! - Diag(Cand->Function->getLocation(), diag::err_ovl_template_candidate) - << getTemplateArgumentBindingsText(FunTmpl->getTemplateParameters(), - *Cand->Function->getTemplateSpecializationArgs()); - } else { - // Normal function - bool errReported = false; - if (!Cand->Viable && Cand->Conversions.size() > 0) { - for (int i = Cand->Conversions.size()-1; i >= 0; i--) { - const ImplicitConversionSequence &Conversion = - Cand->Conversions[i]; - if ((Conversion.ConversionKind != - ImplicitConversionSequence::BadConversion) || - Conversion.ConversionFunctionSet.size() == 0) - continue; - Diag(Cand->Function->getLocation(), - diag::err_ovl_candidate_not_viable) << (i+1); - errReported = true; - for (int j = Conversion.ConversionFunctionSet.size()-1; - j >= 0; j--) { - FunctionDecl *Func = Conversion.ConversionFunctionSet[j]; - Diag(Func->getLocation(), diag::err_ovl_candidate); - } - } - } - if (!errReported) - Diag(Cand->Function->getLocation(), diag::err_ovl_candidate); - } - } else if (Cand->IsSurrogate) { - // Desugar the type of the surrogate down to a function type, - // retaining as many typedefs as possible while still showing - // the function type (and, therefore, its parameter types). - QualType FnType = Cand->Surrogate->getConversionType(); - bool isLValueReference = false; - bool isRValueReference = false; - bool isPointer = false; - if (const LValueReferenceType *FnTypeRef = - FnType->getAs()) { - FnType = FnTypeRef->getPointeeType(); - isLValueReference = true; - } else if (const RValueReferenceType *FnTypeRef = - FnType->getAs()) { - FnType = FnTypeRef->getPointeeType(); - isRValueReference = true; - } - if (const PointerType *FnTypePtr = FnType->getAs()) { - FnType = FnTypePtr->getPointeeType(); - isPointer = true; - } - // Desugar down to a function type. - FnType = QualType(FnType->getAs(), 0); - // Reconstruct the pointer/reference as appropriate. - if (isPointer) FnType = Context.getPointerType(FnType); - if (isRValueReference) FnType = Context.getRValueReferenceType(FnType); - if (isLValueReference) FnType = Context.getLValueReferenceType(FnType); - - Diag(Cand->Surrogate->getLocation(), diag::err_ovl_surrogate_cand) - << FnType; - } else if (OnlyViable) { - assert(Cand->Conversions.size() <= 2 && - "builtin-binary-operator-not-binary"); - std::string TypeStr("operator"); - TypeStr += Opc; - TypeStr += "("; - TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString(); - if (Cand->Conversions.size() == 1) { - TypeStr += ")"; - Diag(OpLoc, diag::err_ovl_builtin_unary_candidate) << TypeStr; - } - else { - TypeStr += ", "; - TypeStr += Cand->BuiltinTypes.ParamTypes[1].getAsString(); - TypeStr += ")"; - Diag(OpLoc, diag::err_ovl_builtin_binary_candidate) << TypeStr; - } - } - else if (!Cand->Viable && !Reported) { - // Non-viability might be due to ambiguous user-defined conversions, - // needed for built-in operators. Report them as well, but only once - // as we have typically many built-in candidates. - unsigned NoOperands = Cand->Conversions.size(); - for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) { - const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx]; - if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion || - ICS.ConversionFunctionSet.empty()) - continue; - if (CXXConversionDecl *Func = dyn_cast( - Cand->Conversions[ArgIdx].ConversionFunctionSet[0])) { - QualType FromTy = - QualType( - static_cast(ICS.UserDefined.Before.FromTypePtr),0); - Diag(OpLoc,diag::note_ambiguous_type_conversion) - << FromTy << Func->getConversionType(); - } - for (unsigned j = 0; j < ICS.ConversionFunctionSet.size(); j++) { - FunctionDecl *Func = - Cand->Conversions[ArgIdx].ConversionFunctionSet[j]; - Diag(Func->getLocation(),diag::err_ovl_candidate); - } - } - Reported = true; + // Sort the candidates by viability and position. Sorting directly would + // be prohibitive, so we make a set of pointers and sort those. + llvm::SmallVector Cands; + if (OCD == OCD_AllCandidates) Cands.reserve(CandidateSet.size()); + for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), + LastCand = CandidateSet.end(); + Cand != LastCand; ++Cand) + if (Cand->Viable || OCD == OCD_AllCandidates) + Cands.push_back(Cand); + std::sort(Cands.begin(), Cands.end(), + CompareOverloadCandidatesForDisplay(*this)); + + bool ReportedAmbiguousConversions = false; + + llvm::SmallVectorImpl::iterator I, E; + for (I = Cands.begin(), E = Cands.end(); I != E; ++I) { + OverloadCandidate *Cand = *I; + + if (Cand->Function) + NoteFunctionCandidate(*this, Cand, Args, NumArgs); + else if (Cand->IsSurrogate) + NoteSurrogateCandidate(*this, Cand); + + // This a builtin candidate. We do not, in general, want to list + // every possible builtin candidate. + else if (Cand->Viable) { + // Generally we only see ambiguities including viable builtin + // operators if overload resolution got screwed up by an + // ambiguous user-defined conversion. + // + // FIXME: It's quite possible for different conversions to see + // different ambiguities, though. + if (!ReportedAmbiguousConversions) { + NoteAmbiguousUserConversions(*this, OpLoc, Cand); + ReportedAmbiguousConversions = true; } + + // If this is a viable builtin, print it. + NoteBuiltinOperatorCandidate(*this, Opc, OpLoc, Cand); } } } @@ -4586,7 +4857,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, PDiag(), PDiag(diag::err_addr_ovl_ambiguous) << TemplateMatches[0]->getDeclName(), - PDiag(diag::err_ovl_template_candidate)); + PDiag(diag::note_ovl_candidate) + << (unsigned) oc_function_template); MarkDeclarationReferenced(From->getLocStart(), Result); return Result; } @@ -4611,7 +4883,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous) << RemainingMatches[0]->getDeclName(); for (unsigned I = 0, N = RemainingMatches.size(); I != N; ++I) - Diag(RemainingMatches[I]->getLocation(), diag::err_ovl_candidate); + NoteOverloadCandidate(RemainingMatches[I]); return 0; } @@ -4681,7 +4953,6 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) { // resulting template argument list is used to generate a single // function template specialization, which is added to the set of // overloaded functions considered. - // FIXME: We don't really want to build the specialization here, do we? FunctionDecl *Specialization = 0; TemplateDeductionInfo Info(Context); if (TemplateDeductionResult Result @@ -4906,13 +5177,13 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_no_viable_function_in_call) << ULE->getName() << Fn->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); break; case OR_Ambiguous: Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_ambiguous_call) << ULE->getName() << Fn->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs); break; case OR_Deleted: @@ -4920,7 +5191,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, << Best->Function->isDeleted() << ULE->getName() << Fn->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); break; } @@ -5075,7 +5346,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, Diag(OpLoc, diag::err_ovl_ambiguous_oper) << UnaryOperator::getOpcodeStr(Opc) << Input->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true, + PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs, UnaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); @@ -5084,7 +5355,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, << Best->Function->isDeleted() << UnaryOperator::getOpcodeStr(Opc) << Input->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); return ExprError(); } @@ -5291,7 +5562,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, assert(Result.isInvalid() && "C++ binary operator overloading is missing candidates!"); if (Result.isInvalid()) - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false, + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2, BinaryOperator::getOpcodeStr(Opc), OpLoc); return move(Result); } @@ -5300,7 +5571,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, Diag(OpLoc, diag::err_ovl_ambiguous_oper) << BinaryOperator::getOpcodeStr(Opc) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true, + PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, 2, BinaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); @@ -5309,9 +5580,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, << Best->Function->isDeleted() << BinaryOperator::getOpcodeStr(Opc) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2); return ExprError(); - } + } // We matched a built-in operator; build it. return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); @@ -5411,22 +5682,23 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, } case OR_No_Viable_Function: { - // No viable function; try to create a built-in operation, which will - // produce an error. Then, show the non-viable candidates. - OwningExprResult Result = - CreateBuiltinArraySubscriptExpr(move(Base), LLoc, move(Idx), RLoc); - assert(Result.isInvalid() && - "C++ subscript operator overloading is missing candidates!"); - if (Result.isInvalid()) - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false, - "[]", LLoc); - return move(Result); + if (CandidateSet.empty()) + Diag(LLoc, diag::err_ovl_no_oper) + << Args[0]->getType() << /*subscript*/ 0 + << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + else + Diag(LLoc, diag::err_ovl_no_viable_subscript) + << Args[0]->getType() + << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2, + "[]", LLoc); + return ExprError(); } case OR_Ambiguous: Diag(LLoc, diag::err_ovl_ambiguous_oper) << "[]" << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true, + PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, 2, "[]", LLoc); return ExprError(); @@ -5434,7 +5706,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, Diag(LLoc, diag::err_ovl_deleted_oper) << Best->Function->isDeleted() << "[]" << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2, + "[]", LLoc); return ExprError(); } @@ -5518,14 +5791,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Diag(UnresExpr->getMemberLoc(), diag::err_ovl_no_viable_member_function_in_call) << DeclName << MemExprE->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); // FIXME: Leaking incoming expressions! return ExprError(); case OR_Ambiguous: Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call) << DeclName << MemExprE->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); // FIXME: Leaking incoming expressions! return ExprError(); @@ -5533,7 +5806,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call) << Best->Function->isDeleted() << DeclName << MemExprE->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); // FIXME: Leaking incoming expressions! return ExprError(); } @@ -5636,9 +5909,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // functions for each conversion function declared in an // accessible base class provided the function is not hidden // within T by another intervening declaration. - // FIXME: Look in base classes for more conversion operators! const UnresolvedSet *Conversions - = cast(Record->getDecl())->getConversionFunctions(); + = cast(Record->getDecl())->getVisibleConversionFunctions(); for (UnresolvedSet::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; @@ -5674,17 +5946,22 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, break; case OR_No_Viable_Function: - Diag(Object->getSourceRange().getBegin(), - diag::err_ovl_no_viable_object_call) - << Object->getType() << Object->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + if (CandidateSet.empty()) + Diag(Object->getSourceRange().getBegin(), diag::err_ovl_no_oper) + << Object->getType() << /*call*/ 1 + << Object->getSourceRange(); + else + Diag(Object->getSourceRange().getBegin(), + diag::err_ovl_no_viable_object_call) + << Object->getType() << Object->getSourceRange(); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); break; case OR_Ambiguous: Diag(Object->getSourceRange().getBegin(), diag::err_ovl_ambiguous_object_call) << Object->getType() << Object->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs); break; case OR_Deleted: @@ -5692,7 +5969,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, diag::err_ovl_deleted_object_call) << Best->Function->isDeleted() << Object->getType() << Object->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); break; } @@ -5873,20 +6150,20 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { else Diag(OpLoc, diag::err_ovl_no_viable_oper) << "operator->" << Base->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, &Base, 1); return ExprError(); case OR_Ambiguous: Diag(OpLoc, diag::err_ovl_ambiguous_oper) << "->" << Base->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, &Base, 1); return ExprError(); case OR_Deleted: Diag(OpLoc, diag::err_ovl_deleted_oper) << Best->Function->isDeleted() << "->" << Base->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, &Base, 1); return ExprError(); } @@ -6020,9 +6297,14 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { MemExpr->getMemberLoc(), Fn->getType(), TemplateArgs); - } else - Base = new (Context) CXXThisExpr(SourceLocation(), - MemExpr->getBaseType()); + } else { + SourceLocation Loc = MemExpr->getMemberLoc(); + if (MemExpr->getQualifier()) + Loc = MemExpr->getQualifierRange().getBegin(); + Base = new (Context) CXXThisExpr(Loc, + MemExpr->getBaseType(), + /*isImplicit=*/true); + } } else Base = MemExpr->getBase()->Retain(); diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 3613d60..20add00 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_SEMA_OVERLOAD_H #include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" #include "clang/AST/Type.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" @@ -149,6 +150,15 @@ namespace clang { /// conversions. CXXConstructorDecl *CopyConstructor; + void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); } + void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); } + QualType getFromType() const { + return QualType::getFromOpaquePtr(FromTypePtr); + } + QualType getToType() const { + return QualType::getFromOpaquePtr(ToTypePtr); + } + void setAsIdentityConversion(); ImplicitConversionRank getRank() const; bool isPointerConversionToBool() const; @@ -190,6 +200,93 @@ namespace clang { void DebugPrint() const; }; + /// Represents an ambiguous user-defined conversion sequence. + struct AmbiguousConversionSequence { + typedef llvm::SmallVector ConversionSet; + + void *FromTypePtr; + void *ToTypePtr; + char Buffer[sizeof(ConversionSet)]; + + QualType getFromType() const { + return QualType::getFromOpaquePtr(FromTypePtr); + } + QualType getToType() const { + return QualType::getFromOpaquePtr(ToTypePtr); + } + void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); } + void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); } + + ConversionSet &conversions() { + return *reinterpret_cast(Buffer); + } + + const ConversionSet &conversions() const { + return *reinterpret_cast(Buffer); + } + + void addConversion(FunctionDecl *D) { + conversions().push_back(D); + } + + typedef ConversionSet::iterator iterator; + iterator begin() { return conversions().begin(); } + iterator end() { return conversions().end(); } + + typedef ConversionSet::const_iterator const_iterator; + const_iterator begin() const { return conversions().begin(); } + const_iterator end() const { return conversions().end(); } + + void construct(); + void destruct(); + void copyFrom(const AmbiguousConversionSequence &); + }; + + /// BadConversionSequence - Records information about an invalid + /// conversion sequence. + struct BadConversionSequence { + enum FailureKind { + no_conversion, + unrelated_class, + suppressed_user, + bad_qualifiers + }; + + // This can be null, e.g. for implicit object arguments. + Expr *FromExpr; + + FailureKind Kind; + + private: + // The type we're converting from (an opaque QualType). + void *FromTy; + + // The type we're converting to (an opaque QualType). + void *ToTy; + + public: + void init(FailureKind K, Expr *From, QualType To) { + init(K, From->getType(), To); + FromExpr = From; + } + void init(FailureKind K, QualType From, QualType To) { + Kind = K; + FromExpr = 0; + setFromType(From); + setToType(To); + } + + QualType getFromType() const { return QualType::getFromOpaquePtr(FromTy); } + QualType getToType() const { return QualType::getFromOpaquePtr(ToTy); } + + void setFromExpr(Expr *E) { + FromExpr = E; + setFromType(E->getType()); + } + void setFromType(QualType T) { FromTy = T.getAsOpaquePtr(); } + void setToType(QualType T) { ToTy = T.getAsOpaquePtr(); } + }; + /// ImplicitConversionSequence - Represents an implicit conversion /// sequence, which may be a standard conversion sequence /// (C++ 13.3.3.1.1), user-defined conversion sequence (C++ 13.3.3.1.2), @@ -197,18 +294,26 @@ namespace clang { struct ImplicitConversionSequence { /// Kind - The kind of implicit conversion sequence. BadConversion /// specifies that there is no conversion from the source type to - /// the target type. The enumerator values are ordered such that - /// better implicit conversions have smaller values. + /// the target type. AmbiguousConversion represents the unique + /// ambiguous conversion (C++0x [over.best.ics]p10). enum Kind { StandardConversion = 0, UserDefinedConversion, + AmbiguousConversion, EllipsisConversion, BadConversion }; + private: /// ConversionKind - The kind of implicit conversion sequence. Kind ConversionKind; + void setKind(Kind K) { + if (isAmbiguous()) Ambiguous.destruct(); + ConversionKind = K; + } + + public: union { /// When ConversionKind == StandardConversion, provides the /// details of the standard conversion sequence. @@ -217,12 +322,58 @@ namespace clang { /// When ConversionKind == UserDefinedConversion, provides the /// details of the user-defined conversion sequence. UserDefinedConversionSequence UserDefined; + + /// When ConversionKind == AmbiguousConversion, provides the + /// details of the ambiguous conversion. + AmbiguousConversionSequence Ambiguous; + + /// When ConversionKind == BadConversion, provides the details + /// of the bad conversion. + BadConversionSequence Bad; }; + + ImplicitConversionSequence() : ConversionKind(BadConversion) {} + ~ImplicitConversionSequence() { + if (isAmbiguous()) Ambiguous.destruct(); + } + ImplicitConversionSequence(const ImplicitConversionSequence &Other) + : ConversionKind(Other.ConversionKind) + { + switch (ConversionKind) { + case StandardConversion: Standard = Other.Standard; break; + case UserDefinedConversion: UserDefined = Other.UserDefined; break; + case AmbiguousConversion: Ambiguous.copyFrom(Other.Ambiguous); break; + case EllipsisConversion: break; + case BadConversion: Bad = Other.Bad; break; + } + } + + ImplicitConversionSequence & + operator=(const ImplicitConversionSequence &Other) { + if (isAmbiguous()) Ambiguous.destruct(); + new (this) ImplicitConversionSequence(Other); + return *this; + } - /// When ConversionKind == BadConversion due to multiple conversion - /// functions, this will list those functions. - llvm::SmallVector ConversionFunctionSet; - + Kind getKind() const { return ConversionKind; } + bool isBad() const { return ConversionKind == BadConversion; } + bool isStandard() const { return ConversionKind == StandardConversion; } + bool isEllipsis() const { return ConversionKind == EllipsisConversion; } + bool isAmbiguous() const { return ConversionKind == AmbiguousConversion; } + bool isUserDefined() const { + return ConversionKind == UserDefinedConversion; + } + + void setBad() { setKind(BadConversion); } + void setStandard() { setKind(StandardConversion); } + void setEllipsis() { setKind(EllipsisConversion); } + void setUserDefined() { setKind(UserDefinedConversion); } + void setAmbiguous() { + if (isAmbiguous()) return; + ConversionKind = AmbiguousConversion; + Ambiguous.construct(); + } + // The result of a comparison between implicit conversion // sequences. Use Sema::CompareImplicitConversionSequences to // actually perform the comparison. @@ -235,6 +386,13 @@ namespace clang { void DebugPrint() const; }; + enum OverloadFailureKind { + ovl_fail_too_many_arguments, + ovl_fail_too_few_arguments, + ovl_fail_bad_conversion, + ovl_fail_bad_deduction + }; + /// OverloadCandidate - A single candidate in an overload set (C++ 13.3). struct OverloadCandidate { /// Function - The actual function that this candidate @@ -275,11 +433,25 @@ namespace clang { /// object argument. bool IgnoreObjectArgument; + /// FailureKind - The reason why this candidate is not viable. + /// Actually an OverloadFailureKind. + unsigned char FailureKind; + /// FinalConversion - For a conversion function (where Function is /// a CXXConversionDecl), the standard conversion that occurs /// after the call to the overload candidate to convert the result /// of calling the conversion function to the required type. StandardConversionSequence FinalConversion; + + /// hasAmbiguousConversion - Returns whether this overload + /// candidate requires an ambiguous conversion or not. + bool hasAmbiguousConversion() const { + for (llvm::SmallVectorImpl::const_iterator + I = Conversions.begin(), E = Conversions.end(); I != E; ++I) { + if (I->isAmbiguous()) return true; + } + return false; + } }; /// OverloadCandidateSet - A set of overload candidates, used in C++ diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index b8928c3..7855a7f 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1157,7 +1157,8 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, MultiExprArg exprs, ExprArg asmString, MultiExprArg clobbers, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + bool MSAsm) { unsigned NumClobbers = clobbers.size(); StringLiteral **Constraints = reinterpret_cast(constraints.get()); @@ -1261,9 +1262,9 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, asmString.release(); clobbers.release(); AsmStmt *NS = - new (Context) AsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, - Names, Constraints, Exprs, AsmString, NumClobbers, - Clobbers, RParenLoc); + new (Context) AsmStmt(AsmLoc, IsSimple, IsVolatile, MSAsm, NumOutputs, + NumInputs, Names, Constraints, Exprs, AsmString, + NumClobbers, Clobbers, RParenLoc); // Validate the asm string, ensuring it makes sense given the operands we // have. llvm::SmallVector Pieces; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 8c6aa6a..2fad832 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -80,6 +80,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, TypeTy *ObjectTypePtr, bool EnteringContext, TemplateTy &TemplateResult) { + assert(getLangOptions().CPlusPlus && "No template names in C!"); + DeclarationName TName; switch (Name.getKind()) { @@ -141,6 +143,30 @@ TemplateNameKind Sema::isTemplateName(Scope *S, return TemplateKind; } +bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, + SourceLocation IILoc, + Scope *S, + const CXXScopeSpec *SS, + TemplateTy &SuggestedTemplate, + TemplateNameKind &SuggestedKind) { + // We can't recover unless there's a dependent scope specifier preceding the + // template name. + if (!SS || !SS->isSet() || !isDependentScopeSpecifier(*SS) || + computeDeclContext(*SS)) + return false; + + // The code is missing a 'template' keyword prior to the dependent template + // name. + NestedNameSpecifier *Qualifier = (NestedNameSpecifier*)SS->getScopeRep(); + Diag(IILoc, diag::err_template_kw_missing) + << Qualifier << II.getName() + << CodeModificationHint::CreateInsertion(IILoc, "template "); + SuggestedTemplate + = TemplateTy::make(Context.getDependentTemplateName(Qualifier, &II)); + SuggestedKind = TNK_Dependent_template_name; + return true; +} + void Sema::LookupTemplateName(LookupResult &Found, Scope *S, const CXXScopeSpec &SS, QualType ObjectType, @@ -192,7 +218,8 @@ void Sema::LookupTemplateName(LookupResult &Found, ObjectTypeSearchedInScope = true; } } else if (isDependent) { - // We cannot look into a dependent object type or + // We cannot look into a dependent object type or nested nme + // specifier. return; } else { // Perform unqualified name lookup in the current scope. @@ -203,7 +230,7 @@ void Sema::LookupTemplateName(LookupResult &Found, assert(!Found.isAmbiguous() && "Cannot handle template name-lookup ambiguities"); - if (Found.empty()) { + if (Found.empty() && !isDependent) { // If we did not find any names, attempt to correct any typos. DeclarationName Name = Found.getLookupName(); if (CorrectTypo(Found, S, &SS, LookupCtx)) { @@ -219,6 +246,9 @@ void Sema::LookupTemplateName(LookupResult &Found, << Name << Found.getLookupName() << CodeModificationHint::CreateReplacement(Found.getNameLoc(), Found.getLookupName().getAsString()); + if (TemplateDecl *Template = Found.getAsSingle()) + Diag(Template->getLocation(), diag::note_previous_decl) + << Template->getDeclName(); } else Found.clear(); } else { @@ -1578,15 +1608,19 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, TemplateTy Template; TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType, EnteringContext, Template); - if (TNK == TNK_Non_template) { + if (TNK == TNK_Non_template && + isCurrentInstantiationWithDependentBases(SS)) { + // This is a dependent template. + } else if (TNK == TNK_Non_template) { Diag(Name.getSourceRange().getBegin(), diag::err_template_kw_refers_to_non_template) << GetNameFromUnqualifiedId(Name) << Name.getSourceRange(); return TemplateTy(); + } else { + // We found something; return it. + return Template; } - - return Template; } NestedNameSpecifier *Qualifier @@ -4537,8 +4571,10 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (CXXMethodDecl *Method = dyn_cast(Prev)) { if (Context.hasSameUnqualifiedType(Method->getType(), R)) { Matches.clear(); + Matches.push_back(Method); - break; + if (Method->getTemplateSpecializationKind() == TSK_Undeclared) + break; } } } @@ -4550,7 +4586,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, TemplateDeductionInfo Info(Context); FunctionDecl *Specialization = 0; if (TemplateDeductionResult TDK - = DeduceTemplateArguments(FunTmpl, + = DeduceTemplateArguments(FunTmpl, (HasExplicitTemplateArgs ? &TemplateArgs : 0), R, Specialization, Info)) { // FIXME: Keep track of almost-matches? @@ -4735,6 +4771,10 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, case LookupResult::NotFound: DiagID = diag::err_typename_nested_not_found; break; + + case LookupResult::NotFoundInCurrentInstantiation: + // Okay, it's a member of an unknown instantiation. + return Context.getTypenameType(NNS, &II); case LookupResult::Found: if (TypeDecl *Type = dyn_cast(Result.getFoundDecl())) { diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 21f7996..7b433e9 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -542,13 +542,13 @@ DeduceTemplateArguments(ASTContext &Context, // type [i] case Type::DependentSizedArray: { - const ArrayType *ArrayArg = dyn_cast(Arg); + const ArrayType *ArrayArg = Context.getAsArrayType(Arg); if (!ArrayArg) return Sema::TDK_NonDeducedMismatch; // Check the element type of the arrays const DependentSizedArrayType *DependentArrayParm - = cast(Param); + = Context.getAsDependentSizedArrayType(Param); if (Sema::TemplateDeductionResult Result = DeduceTemplateArguments(Context, TemplateParams, DependentArrayParm->getElementType(), @@ -1312,20 +1312,18 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, /// \param FunctionTemplate the function template for which we are performing /// template argument deduction. /// -/// \param HasExplicitTemplateArgs whether any template arguments were -/// explicitly specified. -/// -/// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true, -/// the explicitly-specified template arguments. -/// -/// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true, -/// the number of explicitly-specified template arguments in -/// @p ExplicitTemplateArguments. This value may be zero. +/// \param ExplicitTemplateArguments the explicit template arguments provided +/// for this call. /// /// \param Args the function call arguments /// /// \param NumArgs the number of arguments in Args /// +/// \param Name the name of the function being called. This is only significant +/// when the function template is a conversion function template, in which +/// case this routine will also perform template argument deduction based on +/// the function to which +/// /// \param Specialization if template argument deduction was successful, /// this will be set to the function template specialization produced by /// template argument deduction. @@ -1336,7 +1334,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, /// \returns the result of template argument deduction. Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - const TemplateArgumentListInfo *ExplicitTemplateArgs, + const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, FunctionDecl *&Specialization, TemplateDeductionInfo &Info) { @@ -1475,8 +1473,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, return TDK_FailedOverloadResolution; } - // Get the type of the resolved argument. + // Get the type of the resolved argument, and adjust it per + // C++0x [temp.deduct.call]p3. ArgType = ResolvedArg->getType(); + if (!ParamWasReference && ArgType->isFunctionType()) + ArgType = Context.getPointerType(ArgType); if (ArgType->isPointerType() || ArgType->isMemberPointerType()) TDF |= TDF_IgnoreQualifiers; @@ -2173,7 +2174,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to // find other occurrences of template parameters. const DeclRefExpr *DRE = dyn_cast(E); - if (!E) + if (!DRE) return; const NonTypeTemplateParmDecl *NTTP diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index d974f89..2db0deb 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1060,6 +1060,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Exit the scope of this instantiation. CurContext = PreviousContext; + // If this is a polymorphic C++ class without a key function, we'll + // have to mark all of the virtual members to allow emission of a vtable + // in this translation unit. + if (Instantiation->isDynamicClass() && !Context.getKeyFunction(Instantiation)) + ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Instantiation, + PointOfInstantiation)); + if (!Invalid) Consumer.HandleTagDeclDefinition(Instantiation); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index ed30229..9515834 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -743,7 +743,8 @@ QualType Sema::BuildFunctionType(QualType T, bool Variadic, unsigned Quals, SourceLocation Loc, DeclarationName Entity) { if (T->isArrayType() || T->isFunctionType()) { - Diag(Loc, diag::err_func_returning_array_function) << T; + Diag(Loc, diag::err_func_returning_array_function) + << T->isFunctionType() << T; return QualType(); } @@ -896,13 +897,18 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; case UnqualifiedId::IK_ConstructorName: + case UnqualifiedId::IK_ConstructorTemplateId: case UnqualifiedId::IK_DestructorName: - case UnqualifiedId::IK_ConversionFunctionId: // Constructors and destructors don't have return types. Use - // "void" instead. Conversion operators will check their return - // types separately. + // "void" instead. T = Context.VoidTy; break; + + case UnqualifiedId::IK_ConversionFunctionId: + // The result type of a conversion function is the type that it + // converts to. + T = GetTypeFromParser(D.getName().ConversionFunctionId); + break; } if (T.isNull()) @@ -1041,8 +1047,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; // C99 6.7.5.3p1: The return type may not be a function or array type. - if (T->isArrayType() || T->isFunctionType()) { - Diag(DeclType.Loc, diag::err_func_returning_array_function) << T; + // For conversion functions, we'll diagnose this particular error later. + if ((T->isArrayType() || T->isFunctionType()) && + (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId)) { + Diag(DeclType.Loc, diag::err_func_returning_array_function) + << T->isFunctionType() << T; T = Context.IntTy; D.setInvalidType(true); } @@ -1351,6 +1360,20 @@ namespace { cast(TInfo->getTypeLoc()); TL.copy(OldTL); } + void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { + assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr); + TL.setTypeofLoc(DS.getTypeSpecTypeLoc()); + TL.setParensRange(DS.getTypeofParensRange()); + } + void VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { + assert(DS.getTypeSpecType() == DeclSpec::TST_typeofType); + TL.setTypeofLoc(DS.getTypeSpecTypeLoc()); + TL.setParensRange(DS.getTypeofParensRange()); + assert(DS.getTypeRep()); + TypeSourceInfo *TInfo = 0; + Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo); + TL.setUnderlyingTInfo(TInfo); + } void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. TL.initialize(DS.getTypeSpecTypeLoc()); @@ -1461,34 +1484,6 @@ void LocInfoType::getAsStringInternal(std::string &Str, " GetTypeFromParser"); } -/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition -/// declarator -QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) { - ObjCMethodDecl *MDecl = cast(D.getAs()); - QualType T = MDecl->getResultType(); - llvm::SmallVector ArgTys; - - // Add the first two invisible argument types for self and _cmd. - if (MDecl->isInstanceMethod()) { - QualType selfTy = Context.getObjCInterfaceType(MDecl->getClassInterface()); - selfTy = Context.getPointerType(selfTy); - ArgTys.push_back(selfTy); - } else - ArgTys.push_back(Context.getObjCIdType()); - ArgTys.push_back(Context.getObjCSelType()); - - for (ObjCMethodDecl::param_iterator PI = MDecl->param_begin(), - E = MDecl->param_end(); PI != E; ++PI) { - QualType ArgTy = (*PI)->getType(); - assert(!ArgTy.isNull() && "Couldn't parse type?"); - ArgTy = adjustParameterType(ArgTy); - ArgTys.push_back(ArgTy); - } - T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(), - MDecl->isVariadic(), 0); - return T; -} - /// UnwrapSimilarPointerTypes - If T1 and T2 are pointer types that /// may be similar (C++ 4.4), replaces T1 and T2 with the type that /// they point to and return true. If T1 and T2 aren't pointer types diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp new file mode 100644 index 0000000..7c19bf6 --- /dev/null +++ b/lib/Sema/TargetAttributesSema.cpp @@ -0,0 +1,86 @@ +//===-- TargetAttributesSema.cpp - Encapsulate target attributes-*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains semantic analysis implementation for target-specific +// attributes. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "TargetAttributesSema.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/Triple.h" + +using namespace clang; + +TargetAttributesSema::~TargetAttributesSema() {} +bool TargetAttributesSema::ProcessDeclAttribute(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S) const { + return false; +} + +static void HandleMSP430InterruptAttr(Decl *d, + const AttributeList &Attr, Sema &S) { + // Check the attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + + // FIXME: Check for decl - it should be void ()(void). + + Expr *NumParamsExpr = static_cast(Attr.getArg(0)); + llvm::APSInt NumParams(32); + if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + << "interrupt" << NumParamsExpr->getSourceRange(); + return; + } + + unsigned Num = NumParams.getLimitedValue(255); + if ((Num & 1) || Num > 30) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) + << "interrupt" << (int)NumParams.getSExtValue() + << NumParamsExpr->getSourceRange(); + return; + } + + d->addAttr(::new (S.Context) MSP430InterruptAttr(Num)); + d->addAttr(::new (S.Context) UsedAttr()); + } + +namespace { + class MSP430AttributesSema : public TargetAttributesSema { + public: + MSP430AttributesSema() { } + bool ProcessDeclAttribute(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S) const { + if (Attr.getName()->getName() == "interrupt") { + HandleMSP430InterruptAttr(D, Attr, S); + return true; + } + return false; + } + }; +} + +const TargetAttributesSema &Sema::getTargetAttributesSema() const { + if (TheTargetAttributesSema) + return *TheTargetAttributesSema; + + const llvm::Triple &Triple(Context.Target.getTriple()); + switch (Triple.getArch()) { + default: + return *(TheTargetAttributesSema = new TargetAttributesSema); + + case llvm::Triple::msp430: + return *(TheTargetAttributesSema = new MSP430AttributesSema); + } +} + diff --git a/lib/Sema/TargetAttributesSema.h b/lib/Sema/TargetAttributesSema.h new file mode 100644 index 0000000..8794e40 --- /dev/null +++ b/lib/Sema/TargetAttributesSema.h @@ -0,0 +1,27 @@ +//===--- TargetAttributesSema.h - Semantic Analysis For Target Attributes -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_SEMA_TARGETSEMA_H +#define CLANG_SEMA_TARGETSEMA_H + +namespace clang { + class Scope; + class Decl; + class Attr; + class Sema; + + class TargetAttributesSema { + public: + virtual ~TargetAttributesSema(); + virtual bool ProcessDeclAttribute(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S) const; + }; +} + +#endif diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 208c885..445ef0d 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -975,12 +975,15 @@ public: QualType BaseType = ((Expr*) Base.get())->getType(); - // FIXME: wait, this is re-performing lookup? + LookupResult R(getSema(), Member->getDeclName(), MemberLoc, + Sema::LookupMemberName); + R.addDecl(Member); + R.resolveKind(); + return getSema().BuildMemberReferenceExpr(move(Base), BaseType, OpLoc, isArrow, SS, FirstQualifierInScope, - Member->getDeclName(), MemberLoc, - ExplicitTemplateArgs); + R, ExplicitTemplateArgs); } /// \brief Build a new binary operator expression. @@ -1344,9 +1347,11 @@ public: /// semantic analysis. Subclasses may override this routine to provide /// different behavior. OwningExprResult RebuildCXXThisExpr(SourceLocation ThisLoc, - QualType ThisType) { + QualType ThisType, + bool isImplicit) { return getSema().Owned( - new (getSema().Context) CXXThisExpr(ThisLoc, ThisType)); + new (getSema().Context) CXXThisExpr(ThisLoc, ThisType, + isImplicit)); } /// \brief Build a new C++ throw expression. @@ -1559,6 +1564,7 @@ public: bool IsArrow, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, + NamedDecl *FirstQualifierInScope, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { CXXScopeSpec SS; @@ -1567,7 +1573,8 @@ public: return SemaRef.BuildMemberReferenceExpr(move(BaseE), BaseType, OperatorLoc, IsArrow, - SS, R, TemplateArgs); + SS, FirstQualifierInScope, + R, TemplateArgs); } /// \brief Build a new Objective-C @encode expression. @@ -2617,18 +2624,16 @@ QualType TreeTransform::TransformTypedefType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformTypeOfExprType(TypeLocBuilder &TLB, TypeOfExprTypeLoc TL) { - TypeOfExprType *T = TL.getTypePtr(); - // typeof expressions are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); - Sema::OwningExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr()); + Sema::OwningExprResult E = getDerived().TransformExpr(TL.getUnderlyingExpr()); if (E.isInvalid()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || - E.get() != T->getUnderlyingExpr()) { + E.get() != TL.getUnderlyingExpr()) { Result = getDerived().RebuildTypeOfExprType(move(E)); if (Result.isNull()) return QualType(); @@ -2636,7 +2641,9 @@ QualType TreeTransform::TransformTypeOfExprType(TypeLocBuilder &TLB, else E.take(); TypeOfExprTypeLoc NewTL = TLB.push(Result); - NewTL.setNameLoc(TL.getNameLoc()); + NewTL.setTypeofLoc(TL.getTypeofLoc()); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); return Result; } @@ -2644,23 +2651,23 @@ QualType TreeTransform::TransformTypeOfExprType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformTypeOfType(TypeLocBuilder &TLB, TypeOfTypeLoc TL) { - TypeOfType *T = TL.getTypePtr(); - - // FIXME: should be an inner type, or at least have a TypeSourceInfo. - QualType Underlying = getDerived().TransformType(T->getUnderlyingType()); - if (Underlying.isNull()) + TypeSourceInfo* Old_Under_TI = TL.getUnderlyingTInfo(); + TypeSourceInfo* New_Under_TI = getDerived().TransformType(Old_Under_TI); + if (!New_Under_TI) return QualType(); QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || - Underlying != T->getUnderlyingType()) { - Result = getDerived().RebuildTypeOfType(Underlying); + if (getDerived().AlwaysRebuild() || New_Under_TI != Old_Under_TI) { + Result = getDerived().RebuildTypeOfType(New_Under_TI->getType()); if (Result.isNull()) return QualType(); } TypeOfTypeLoc NewTL = TLB.push(Result); - NewTL.setNameLoc(TL.getNameLoc()); + NewTL.setTypeofLoc(TL.getTypeofLoc()); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + NewTL.setUnderlyingTInfo(New_Under_TI); return Result; } @@ -3711,6 +3718,12 @@ TreeTransform::TransformMemberExpr(MemberExpr *E) { SourceLocation FakeOperatorLoc = SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd()); + // FIXME: to do this check properly, we will need to preserve the + // first-qualifier-in-scope here, just in case we had a dependent + // base (and therefore couldn't do the check) and a + // nested-name-qualifier (and therefore could do the lookup). + NamedDecl *FirstQualifierInScope = 0; + return getDerived().RebuildMemberExpr(move(Base), FakeOperatorLoc, E->isArrow(), Qualifier, @@ -3719,7 +3732,7 @@ TreeTransform::TransformMemberExpr(MemberExpr *E) { Member, (E->hasExplicitTemplateArgumentList() ? &TransArgs : 0), - 0); + FirstQualifierInScope); } template @@ -4386,7 +4399,7 @@ TreeTransform::TransformCXXThisExpr(CXXThisExpr *E) { T == E->getType()) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCXXThisExpr(E->getLocStart(), T); + return getDerived().RebuildCXXThisExpr(E->getLocStart(), T, E->isImplicit()); } template @@ -5027,6 +5040,12 @@ TreeTransform::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) TransArgs.addArgument(Loc); } } + + // FIXME: to do this check properly, we will need to preserve the + // first-qualifier-in-scope here, just in case we had a dependent + // base (and therefore couldn't do the check) and a + // nested-name-qualifier (and therefore could do the lookup). + NamedDecl *FirstQualifierInScope = 0; return getDerived().RebuildUnresolvedMemberExpr(move(Base), BaseType, @@ -5034,6 +5053,7 @@ TreeTransform::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) Old->isArrow(), Qualifier, Old->getQualifierRange(), + FirstQualifierInScope, R, (Old->hasExplicitTemplateArgs() ? &TransArgs : 0)); -- cgit v1.1