示例#1
0
文件: Sema.cpp 项目: dmpots/clang
/// \brief Give notes for a set of overloads.
///
/// A companion to isExprCallable. In cases when the name that the programmer
/// wrote was an overloaded function, we may be able to make some guesses about
/// plausible overloads based on their return types; such guesses can be handed
/// off to this method to be emitted as notes.
///
/// \param Overloads - The overloads to note.
/// \param FinalNoteLoc - If we've suppressed printing some overloads due to
///  -fshow-overloads=best, this is the location to attach to the note about too
///  many candidates. Typically this will be the location of the original
///  ill-formed expression.
static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads,
                          const SourceLocation FinalNoteLoc) {
  int ShownOverloads = 0;
  int SuppressedOverloads = 0;
  for (UnresolvedSetImpl::iterator It = Overloads.begin(),
       DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
    // FIXME: Magic number for max shown overloads stolen from
    // OverloadCandidateSet::NoteCandidates.
    if (ShownOverloads >= 4 && S.Diags.getShowOverloads() == Ovl_Best) {
      ++SuppressedOverloads;
      continue;
    }

    NamedDecl *Fn = (*It)->getUnderlyingDecl();
    S.Diag(Fn->getLocation(), diag::note_possible_target_of_call);
    ++ShownOverloads;
  }

  if (SuppressedOverloads)
    S.Diag(FinalNoteLoc, diag::note_ovl_too_many_candidates)
      << SuppressedOverloads;
}
/// \brief Build a new nested-name-specifier for "identifier::", as described
/// by ActOnCXXNestedNameSpecifier.
///
/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
/// that it contains an extra parameter \p ScopeLookupResult, which provides
/// the result of name lookup within the scope of the nested-name-specifier
/// that was computed at template definition time.
///
/// If ErrorRecoveryLookup is true, then this call is used to improve error
/// recovery.  This means that it should not emit diagnostics, it should
/// just return true on failure.  It also means it should only return a valid
/// scope if it *knows* that the result is correct.  It should not return in a
/// dependent context, for example. Nor will it extend \p SS with the scope
/// specifier.
bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
                                       IdentifierInfo &Identifier,
                                       SourceLocation IdentifierLoc,
                                       SourceLocation CCLoc,
                                       QualType ObjectType,
                                       bool EnteringContext,
                                       CXXScopeSpec &SS,
                                       NamedDecl *ScopeLookupResult,
                                       bool ErrorRecoveryLookup) {
  LookupResult Found(*this, &Identifier, IdentifierLoc, 
                     LookupNestedNameSpecifierName);

  // Determine where to perform name lookup
  DeclContext *LookupCtx = 0;
  bool isDependent = false;
  if (!ObjectType.isNull()) {
    // This nested-name-specifier occurs in a member access expression, e.g.,
    // x->B::f, and we are looking into the type of the object.
    assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
    LookupCtx = computeDeclContext(ObjectType);
    isDependent = ObjectType->isDependentType();
  } else if (SS.isSet()) {
    // This nested-name-specifier occurs after another nested-name-specifier,
    // so look into the context associated with the prior nested-name-specifier.
    LookupCtx = computeDeclContext(SS, EnteringContext);
    isDependent = isDependentScopeSpecifier(SS);
    Found.setContextRange(SS.getRange());
  }


  bool ObjectTypeSearchedInScope = false;
  if (LookupCtx) {
    // Perform "qualified" name lookup into the declaration context we
    // computed, which is either the type of the base of a member access
    // expression or the declaration context associated with a prior
    // nested-name-specifier.

    // The declaration context must be complete.
    if (!LookupCtx->isDependentContext() &&
        RequireCompleteDeclContext(SS, LookupCtx))
      return true;

    LookupQualifiedName(Found, LookupCtx);

    if (!ObjectType.isNull() && Found.empty()) {
      // C++ [basic.lookup.classref]p4:
      //   If the id-expression in a class member access is a qualified-id of
      //   the form
      //
      //        class-name-or-namespace-name::...
      //
      //   the class-name-or-namespace-name following the . or -> operator is
      //   looked up both in the context of the entire postfix-expression and in
      //   the scope of the class of the object expression. If the name is found
      //   only in the scope of the class of the object expression, the name
      //   shall refer to a class-name. If the name is found only in the
      //   context of the entire postfix-expression, the name shall refer to a
      //   class-name or namespace-name. [...]
      //
      // Qualified name lookup into a class will not find a namespace-name,
      // so we do not need to diagnose that case specifically. However,
      // this qualified name lookup may find nothing. In that case, perform
      // unqualified name lookup in the given scope (if available) or
      // reconstruct the result from when name lookup was performed at template
      // definition time.
      if (S)
        LookupName(Found, S);
      else if (ScopeLookupResult)
        Found.addDecl(ScopeLookupResult);

      ObjectTypeSearchedInScope = true;
    }
  } else if (!isDependent) {
    // Perform unqualified name lookup in the current scope.
    LookupName(Found, S);
  }

  // If we performed lookup into a dependent context and did not find anything,
  // that's fine: just build a dependent nested-name-specifier.
  if (Found.empty() && isDependent &&
      !(LookupCtx && LookupCtx->isRecord() &&
        (!cast<CXXRecordDecl>(LookupCtx)->hasDefinition() ||
         !cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()))) {
    // Don't speculate if we're just trying to improve error recovery.
    if (ErrorRecoveryLookup)
      return true;
    
    // We were not able to compute the declaration context for a dependent
    // base object type or prior nested-name-specifier, so this
    // nested-name-specifier refers to an unknown specialization. Just build
    // a dependent nested-name-specifier.
    SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc);
    return false;
  } 
  
  // FIXME: Deal with ambiguities cleanly.

  if (Found.empty() && !ErrorRecoveryLookup) {
    // We haven't found anything, and we're not recovering from a
    // different kind of error, so look for typos.
    DeclarationName Name = Found.getLookupName();
    TypoCorrection Corrected;
    Found.clear();
    if ((Corrected = CorrectTypo(Found.getLookupNameInfo(),
                                 Found.getLookupKind(), S, &SS, LookupCtx,
                                 EnteringContext, CTC_NoKeywords)) &&
        isAcceptableNestedNameSpecifier(Corrected.getCorrectionDecl())) {
      std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
      std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
      if (LookupCtx)
        Diag(Found.getNameLoc(), diag::err_no_member_suggest)
          << Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
          << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
      else
        Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest)
          << Name << CorrectedQuotedStr
          << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
      
      if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
        Diag(ND->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr;
        Found.addDecl(ND);
      }
      Found.setLookupName(Corrected.getCorrection());
    } else {
      Found.setLookupName(&Identifier);
    }
  }

  NamedDecl *SD = Found.getAsSingle<NamedDecl>();
  if (isAcceptableNestedNameSpecifier(SD)) {
    if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) {
      // C++ [basic.lookup.classref]p4:
      //   [...] If the name is found in both contexts, the
      //   class-name-or-namespace-name shall refer to the same entity.
      //
      // We already found the name in the scope of the object. Now, look
      // into the current scope (the scope of the postfix-expression) to
      // see if we can find the same name there. As above, if there is no
      // scope, reconstruct the result from the template instantiation itself.
      NamedDecl *OuterDecl;
      if (S) {
        LookupResult FoundOuter(*this, &Identifier, IdentifierLoc, 
                                LookupNestedNameSpecifierName);
        LookupName(FoundOuter, S);
        OuterDecl = FoundOuter.getAsSingle<NamedDecl>();
      } else
        OuterDecl = ScopeLookupResult;

      if (isAcceptableNestedNameSpecifier(OuterDecl) &&
          OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() &&
          (!isa<TypeDecl>(OuterDecl) || !isa<TypeDecl>(SD) ||
           !Context.hasSameType(
                            Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)),
                               Context.getTypeDeclType(cast<TypeDecl>(SD))))) {
         if (ErrorRecoveryLookup)
           return true;

         Diag(IdentifierLoc, 
              diag::err_nested_name_member_ref_lookup_ambiguous)
           << &Identifier;
         Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type)
           << ObjectType;
         Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope);

         // Fall through so that we'll pick the name we found in the object
         // type, since that's probably what the user wanted anyway.
       }
    }

    // If we're just performing this lookup for error-recovery purposes, 
    // don't extend the nested-name-specifier. Just return now.
    if (ErrorRecoveryLookup)
      return false;
    
    if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD)) {
      SS.Extend(Context, Namespace, IdentifierLoc, CCLoc);
      return false;
    }

    if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD)) {
      SS.Extend(Context, Alias, IdentifierLoc, CCLoc);
      return false;
    }

    QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
    TypeLocBuilder TLB;
    if (isa<InjectedClassNameType>(T)) {
      InjectedClassNameTypeLoc InjectedTL
        = TLB.push<InjectedClassNameTypeLoc>(T);
      InjectedTL.setNameLoc(IdentifierLoc);
    } else if (isa<RecordType>(T)) {
      RecordTypeLoc RecordTL = TLB.push<RecordTypeLoc>(T);
      RecordTL.setNameLoc(IdentifierLoc);
    } else if (isa<TypedefType>(T)) {
      TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(T);
      TypedefTL.setNameLoc(IdentifierLoc);
    } else if (isa<EnumType>(T)) {
      EnumTypeLoc EnumTL = TLB.push<EnumTypeLoc>(T);
      EnumTL.setNameLoc(IdentifierLoc);
    } else if (isa<TemplateTypeParmType>(T)) {
      TemplateTypeParmTypeLoc TemplateTypeTL
        = TLB.push<TemplateTypeParmTypeLoc>(T);
      TemplateTypeTL.setNameLoc(IdentifierLoc);
    } else if (isa<UnresolvedUsingType>(T)) {
      UnresolvedUsingTypeLoc UnresolvedTL
        = TLB.push<UnresolvedUsingTypeLoc>(T);
      UnresolvedTL.setNameLoc(IdentifierLoc);
    } else if (isa<SubstTemplateTypeParmType>(T)) {
      SubstTemplateTypeParmTypeLoc TL 
        = TLB.push<SubstTemplateTypeParmTypeLoc>(T);
      TL.setNameLoc(IdentifierLoc);
    } else if (isa<SubstTemplateTypeParmPackType>(T)) {
      SubstTemplateTypeParmPackTypeLoc TL
        = TLB.push<SubstTemplateTypeParmPackTypeLoc>(T);
      TL.setNameLoc(IdentifierLoc);
    } else {
      llvm_unreachable("Unhandled TypeDecl node in nested-name-specifier");
    }

    if (T->isEnumeralType())
      Diag(IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec);

    SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T),
              CCLoc);
    return false;
  }

  // Otherwise, we have an error case.  If we don't want diagnostics, just
  // return an error now.
  if (ErrorRecoveryLookup)
    return true;

  // If we didn't find anything during our lookup, try again with
  // ordinary name lookup, which can help us produce better error
  // messages.
  if (Found.empty()) {
    Found.clear(LookupOrdinaryName);
    LookupName(Found, S);
  }

  // In Microsoft mode, if we are within a templated function and we can't
  // resolve Identifier, then extend the SS with Identifier. This will have 
  // the effect of resolving Identifier during template instantiation. 
  // The goal is to be able to resolve a function call whose
  // nested-name-specifier is located inside a dependent base class.
  // Example: 
  //
  // class C {
  // public:
  //    static void foo2() {  }
  // };
  // template <class T> class A { public: typedef C D; };
  //
  // template <class T> class B : public A<T> {
  // public:
  //   void foo() { D::foo2(); }
  // };
  if (getLangOptions().MicrosoftExt) {
    DeclContext *DC = LookupCtx ? LookupCtx : CurContext;
    if (DC->isDependentContext() && DC->isFunctionOrMethod()) {
      SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc);
      return false;
    }
  }

  unsigned DiagID;
  if (!Found.empty())
    DiagID = diag::err_expected_class_or_namespace;
  else if (SS.isSet()) {
    Diag(IdentifierLoc, diag::err_no_member) 
      << &Identifier << LookupCtx << SS.getRange();
    return true;
  } else
    DiagID = diag::err_undeclared_var_use;

  if (SS.isSet())
    Diag(IdentifierLoc, DiagID) << &Identifier << SS.getRange();
  else
    Diag(IdentifierLoc, DiagID) << &Identifier;

  return true;
}
示例#3
0
/// Build a new nested-name-specifier for "identifier::", as described
/// by ActOnCXXNestedNameSpecifier.
///
/// \param S Scope in which the nested-name-specifier occurs.
/// \param IdInfo Parser information about an identifier in the
///        nested-name-spec.
/// \param EnteringContext If true, enter the context specified by the
///        nested-name-specifier.
/// \param SS Optional nested name specifier preceding the identifier.
/// \param ScopeLookupResult Provides the result of name lookup within the
///        scope of the nested-name-specifier that was computed at template
///        definition time.
/// \param ErrorRecoveryLookup Specifies if the method is called to improve
///        error recovery and what kind of recovery is performed.
/// \param IsCorrectedToColon If not null, suggestion of replace '::' -> ':'
///        are allowed.  The bool value pointed by this parameter is set to
///       'true' if the identifier is treated as if it was followed by ':',
///        not '::'.
/// \param OnlyNamespace If true, only considers namespaces in lookup.
///
/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
/// that it contains an extra parameter \p ScopeLookupResult, which provides
/// the result of name lookup within the scope of the nested-name-specifier
/// that was computed at template definition time.
///
/// If ErrorRecoveryLookup is true, then this call is used to improve error
/// recovery.  This means that it should not emit diagnostics, it should
/// just return true on failure.  It also means it should only return a valid
/// scope if it *knows* that the result is correct.  It should not return in a
/// dependent context, for example. Nor will it extend \p SS with the scope
/// specifier.
bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
                                       bool EnteringContext, CXXScopeSpec &SS,
                                       NamedDecl *ScopeLookupResult,
                                       bool ErrorRecoveryLookup,
                                       bool *IsCorrectedToColon,
                                       bool OnlyNamespace) {
  if (IdInfo.Identifier->isEditorPlaceholder())
    return true;
  LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc,
                     OnlyNamespace ? LookupNamespaceName
                                   : LookupNestedNameSpecifierName);
  QualType ObjectType = GetTypeFromParser(IdInfo.ObjectType);

  // Determine where to perform name lookup
  DeclContext *LookupCtx = nullptr;
  bool isDependent = false;
  if (IsCorrectedToColon)
    *IsCorrectedToColon = false;
  if (!ObjectType.isNull()) {
    // This nested-name-specifier occurs in a member access expression, e.g.,
    // x->B::f, and we are looking into the type of the object.
    assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
    LookupCtx = computeDeclContext(ObjectType);
    isDependent = ObjectType->isDependentType();
  } else if (SS.isSet()) {
    // This nested-name-specifier occurs after another nested-name-specifier,
    // so look into the context associated with the prior nested-name-specifier.
    LookupCtx = computeDeclContext(SS, EnteringContext);
    isDependent = isDependentScopeSpecifier(SS);
    Found.setContextRange(SS.getRange());
  }

  bool ObjectTypeSearchedInScope = false;
  if (LookupCtx) {
    // Perform "qualified" name lookup into the declaration context we
    // computed, which is either the type of the base of a member access
    // expression or the declaration context associated with a prior
    // nested-name-specifier.

    // The declaration context must be complete.
    if (!LookupCtx->isDependentContext() &&
        RequireCompleteDeclContext(SS, LookupCtx))
      return true;

    LookupQualifiedName(Found, LookupCtx);

    if (!ObjectType.isNull() && Found.empty()) {
      // C++ [basic.lookup.classref]p4:
      //   If the id-expression in a class member access is a qualified-id of
      //   the form
      //
      //        class-name-or-namespace-name::...
      //
      //   the class-name-or-namespace-name following the . or -> operator is
      //   looked up both in the context of the entire postfix-expression and in
      //   the scope of the class of the object expression. If the name is found
      //   only in the scope of the class of the object expression, the name
      //   shall refer to a class-name. If the name is found only in the
      //   context of the entire postfix-expression, the name shall refer to a
      //   class-name or namespace-name. [...]
      //
      // Qualified name lookup into a class will not find a namespace-name,
      // so we do not need to diagnose that case specifically. However,
      // this qualified name lookup may find nothing. In that case, perform
      // unqualified name lookup in the given scope (if available) or
      // reconstruct the result from when name lookup was performed at template
      // definition time.
      if (S)
        LookupName(Found, S);
      else if (ScopeLookupResult)
        Found.addDecl(ScopeLookupResult);

      ObjectTypeSearchedInScope = true;
    }
  } else if (!isDependent) {
    // Perform unqualified name lookup in the current scope.
    LookupName(Found, S);
  }

  if (Found.isAmbiguous())
    return true;

  // If we performed lookup into a dependent context and did not find anything,
  // that's fine: just build a dependent nested-name-specifier.
  if (Found.empty() && isDependent &&
      !(LookupCtx && LookupCtx->isRecord() &&
        (!cast<CXXRecordDecl>(LookupCtx)->hasDefinition() ||
         !cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()))) {
    // Don't speculate if we're just trying to improve error recovery.
    if (ErrorRecoveryLookup)
      return true;

    // We were not able to compute the declaration context for a dependent
    // base object type or prior nested-name-specifier, so this
    // nested-name-specifier refers to an unknown specialization. Just build
    // a dependent nested-name-specifier.
    SS.Extend(Context, IdInfo.Identifier, IdInfo.IdentifierLoc, IdInfo.CCLoc);
    return false;
  }

  if (Found.empty() && !ErrorRecoveryLookup) {
    // If identifier is not found as class-name-or-namespace-name, but is found
    // as other entity, don't look for typos.
    LookupResult R(*this, Found.getLookupNameInfo(), LookupOrdinaryName);
    if (LookupCtx)
      LookupQualifiedName(R, LookupCtx);
    else if (S && !isDependent)
      LookupName(R, S);
    if (!R.empty()) {
      // Don't diagnose problems with this speculative lookup.
      R.suppressDiagnostics();
      // The identifier is found in ordinary lookup. If correction to colon is
      // allowed, suggest replacement to ':'.
      if (IsCorrectedToColon) {
        *IsCorrectedToColon = true;
        Diag(IdInfo.CCLoc, diag::err_nested_name_spec_is_not_class)
            << IdInfo.Identifier << getLangOpts().CPlusPlus
            << FixItHint::CreateReplacement(IdInfo.CCLoc, ":");
        if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
          Diag(ND->getLocation(), diag::note_declared_at);
        return true;
      }
      // Replacement '::' -> ':' is not allowed, just issue respective error.
      Diag(R.getNameLoc(), OnlyNamespace
                               ? unsigned(diag::err_expected_namespace_name)
                               : unsigned(diag::err_expected_class_or_namespace))
          << IdInfo.Identifier << getLangOpts().CPlusPlus;
      if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
        Diag(ND->getLocation(), diag::note_entity_declared_at)
            << IdInfo.Identifier;
      return true;
    }
  }

  if (Found.empty() && !ErrorRecoveryLookup && !getLangOpts().MSVCCompat) {
    // We haven't found anything, and we're not recovering from a
    // different kind of error, so look for typos.
    DeclarationName Name = Found.getLookupName();
    Found.clear();
    NestedNameSpecifierValidatorCCC CCC(*this);
    if (TypoCorrection Corrected = CorrectTypo(
            Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS, CCC,
            CTK_ErrorRecovery, LookupCtx, EnteringContext)) {
      if (LookupCtx) {
        bool DroppedSpecifier =
            Corrected.WillReplaceSpecifier() &&
            Name.getAsString() == Corrected.getAsString(getLangOpts());
        if (DroppedSpecifier)
          SS.clear();
        diagnoseTypo(Corrected, PDiag(diag::err_no_member_suggest)
                                  << Name << LookupCtx << DroppedSpecifier
                                  << SS.getRange());
      } else
        diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest)
                                  << Name);

      if (Corrected.getCorrectionSpecifier())
        SS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(),
                       SourceRange(Found.getNameLoc()));

      if (NamedDecl *ND = Corrected.getFoundDecl())
        Found.addDecl(ND);
      Found.setLookupName(Corrected.getCorrection());
    } else {
      Found.setLookupName(IdInfo.Identifier);
    }
  }

  NamedDecl *SD =
      Found.isSingleResult() ? Found.getRepresentativeDecl() : nullptr;
  bool IsExtension = false;
  bool AcceptSpec = isAcceptableNestedNameSpecifier(SD, &IsExtension);
  if (!AcceptSpec && IsExtension) {
    AcceptSpec = true;
    Diag(IdInfo.IdentifierLoc, diag::ext_nested_name_spec_is_enum);
  }
  if (AcceptSpec) {
    if (!ObjectType.isNull() && !ObjectTypeSearchedInScope &&
        !getLangOpts().CPlusPlus11) {
      // C++03 [basic.lookup.classref]p4:
      //   [...] If the name is found in both contexts, the
      //   class-name-or-namespace-name shall refer to the same entity.
      //
      // We already found the name in the scope of the object. Now, look
      // into the current scope (the scope of the postfix-expression) to
      // see if we can find the same name there. As above, if there is no
      // scope, reconstruct the result from the template instantiation itself.
      //
      // Note that C++11 does *not* perform this redundant lookup.
      NamedDecl *OuterDecl;
      if (S) {
        LookupResult FoundOuter(*this, IdInfo.Identifier, IdInfo.IdentifierLoc,
                                LookupNestedNameSpecifierName);
        LookupName(FoundOuter, S);
        OuterDecl = FoundOuter.getAsSingle<NamedDecl>();
      } else
        OuterDecl = ScopeLookupResult;

      if (isAcceptableNestedNameSpecifier(OuterDecl) &&
          OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() &&
          (!isa<TypeDecl>(OuterDecl) || !isa<TypeDecl>(SD) ||
           !Context.hasSameType(
                            Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)),
                               Context.getTypeDeclType(cast<TypeDecl>(SD))))) {
        if (ErrorRecoveryLookup)
          return true;

         Diag(IdInfo.IdentifierLoc,
              diag::err_nested_name_member_ref_lookup_ambiguous)
           << IdInfo.Identifier;
         Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type)
           << ObjectType;
         Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope);

         // Fall through so that we'll pick the name we found in the object
         // type, since that's probably what the user wanted anyway.
       }
    }

    if (auto *TD = dyn_cast_or_null<TypedefNameDecl>(SD))
      MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);

    // If we're just performing this lookup for error-recovery purposes,
    // don't extend the nested-name-specifier. Just return now.
    if (ErrorRecoveryLookup)
      return false;

    // The use of a nested name specifier may trigger deprecation warnings.
    DiagnoseUseOfDecl(SD, IdInfo.CCLoc);

    if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD)) {
      SS.Extend(Context, Namespace, IdInfo.IdentifierLoc, IdInfo.CCLoc);
      return false;
    }

    if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD)) {
      SS.Extend(Context, Alias, IdInfo.IdentifierLoc, IdInfo.CCLoc);
      return false;
    }

    QualType T =
        Context.getTypeDeclType(cast<TypeDecl>(SD->getUnderlyingDecl()));
    TypeLocBuilder TLB;
    if (isa<InjectedClassNameType>(T)) {
      InjectedClassNameTypeLoc InjectedTL
        = TLB.push<InjectedClassNameTypeLoc>(T);
      InjectedTL.setNameLoc(IdInfo.IdentifierLoc);
    } else if (isa<RecordType>(T)) {
      RecordTypeLoc RecordTL = TLB.push<RecordTypeLoc>(T);
      RecordTL.setNameLoc(IdInfo.IdentifierLoc);
    } else if (isa<TypedefType>(T)) {
      TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(T);
      TypedefTL.setNameLoc(IdInfo.IdentifierLoc);
    } else if (isa<EnumType>(T)) {
      EnumTypeLoc EnumTL = TLB.push<EnumTypeLoc>(T);
      EnumTL.setNameLoc(IdInfo.IdentifierLoc);
    } else if (isa<TemplateTypeParmType>(T)) {
      TemplateTypeParmTypeLoc TemplateTypeTL
        = TLB.push<TemplateTypeParmTypeLoc>(T);
      TemplateTypeTL.setNameLoc(IdInfo.IdentifierLoc);
    } else if (isa<UnresolvedUsingType>(T)) {
      UnresolvedUsingTypeLoc UnresolvedTL
        = TLB.push<UnresolvedUsingTypeLoc>(T);
      UnresolvedTL.setNameLoc(IdInfo.IdentifierLoc);
    } else if (isa<SubstTemplateTypeParmType>(T)) {
      SubstTemplateTypeParmTypeLoc TL
        = TLB.push<SubstTemplateTypeParmTypeLoc>(T);
      TL.setNameLoc(IdInfo.IdentifierLoc);
    } else if (isa<SubstTemplateTypeParmPackType>(T)) {
      SubstTemplateTypeParmPackTypeLoc TL
        = TLB.push<SubstTemplateTypeParmPackTypeLoc>(T);
      TL.setNameLoc(IdInfo.IdentifierLoc);
    } else {
      llvm_unreachable("Unhandled TypeDecl node in nested-name-specifier");
    }

    if (T->isEnumeralType())
      Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec);

    SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T),
              IdInfo.CCLoc);
    return false;
  }

  // Otherwise, we have an error case.  If we don't want diagnostics, just
  // return an error now.
  if (ErrorRecoveryLookup)
    return true;

  // If we didn't find anything during our lookup, try again with
  // ordinary name lookup, which can help us produce better error
  // messages.
  if (Found.empty()) {
    Found.clear(LookupOrdinaryName);
    LookupName(Found, S);
  }

  // In Microsoft mode, if we are within a templated function and we can't
  // resolve Identifier, then extend the SS with Identifier. This will have
  // the effect of resolving Identifier during template instantiation.
  // The goal is to be able to resolve a function call whose
  // nested-name-specifier is located inside a dependent base class.
  // Example:
  //
  // class C {
  // public:
  //    static void foo2() {  }
  // };
  // template <class T> class A { public: typedef C D; };
  //
  // template <class T> class B : public A<T> {
  // public:
  //   void foo() { D::foo2(); }
  // };
  if (getLangOpts().MSVCCompat) {
    DeclContext *DC = LookupCtx ? LookupCtx : CurContext;
    if (DC->isDependentContext() && DC->isFunctionOrMethod()) {
      CXXRecordDecl *ContainingClass = dyn_cast<CXXRecordDecl>(DC->getParent());
      if (ContainingClass && ContainingClass->hasAnyDependentBases()) {
        Diag(IdInfo.IdentifierLoc,
             diag::ext_undeclared_unqual_id_with_dependent_base)
            << IdInfo.Identifier << ContainingClass;
        SS.Extend(Context, IdInfo.Identifier, IdInfo.IdentifierLoc,
                  IdInfo.CCLoc);
        return false;
      }
    }
  }

  if (!Found.empty()) {
    if (TypeDecl *TD = Found.getAsSingle<TypeDecl>())
      Diag(IdInfo.IdentifierLoc, diag::err_expected_class_or_namespace)
          << Context.getTypeDeclType(TD) << getLangOpts().CPlusPlus;
    else {
      Diag(IdInfo.IdentifierLoc, diag::err_expected_class_or_namespace)
          << IdInfo.Identifier << getLangOpts().CPlusPlus;
      if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
        Diag(ND->getLocation(), diag::note_entity_declared_at)
            << IdInfo.Identifier;
    }
  } else if (SS.isSet())
    Diag(IdInfo.IdentifierLoc, diag::err_no_member) << IdInfo.Identifier
        << LookupCtx << SS.getRange();
  else
    Diag(IdInfo.IdentifierLoc, diag::err_undeclared_var_use)
        << IdInfo.Identifier;

  return true;
}
示例#4
0
  bool DeclExtractor::CheckTagDeclaration(TagDecl* NewTD,
                                          LookupResult& Previous){
    // If the decl is already known invalid, don't check it.
    if (NewTD->isInvalidDecl())
      return false;

    IdentifierInfo* Name = NewTD->getIdentifier();
    // If this is not a definition, it must have a name.
    assert((Name != 0 || NewTD->isThisDeclarationADefinition()) &&
           "Nameless record must be a definition!");

    // Figure out the underlying type if this a enum declaration. We need to do
    // this early, because it's needed to detect if this is an incompatible
    // redeclaration.

    TagDecl::TagKind Kind = NewTD->getTagKind();
    bool Invalid = false;
    assert(NewTD->getNumTemplateParameterLists() == 0
           && "Cannot handle that yet!");
    bool isExplicitSpecialization = false;

    if (Kind == TTK_Enum) {
      EnumDecl* ED = cast<EnumDecl>(NewTD);
      bool ScopedEnum = ED->isScoped();
      const QualType QT = ED->getIntegerType();

      if (QT.isNull() && ScopedEnum)
        // No underlying type explicitly specified, or we failed to parse the
        // type, default to int.
        ; //EnumUnderlying = m_Context->IntTy.getTypePtr();
      else if (!QT.isNull()) {
        // C++0x 7.2p2: The type-specifier-seq of an enum-base shall name an
        // integral type; any cv-qualification is ignored.

        SourceLocation UnderlyingLoc;
        TypeSourceInfo* TI = 0;
        if ((TI = ED->getIntegerTypeSourceInfo()))
          UnderlyingLoc = TI->getTypeLoc().getBeginLoc();

        if (!QT->isDependentType() && !QT->isIntegralType(*m_Context)) {
          m_Sema->Diag(UnderlyingLoc, diag::err_enum_invalid_underlying)
            << QT;
        }
        if (TI)
          m_Sema->DiagnoseUnexpandedParameterPack(UnderlyingLoc, TI,
                                                Sema::UPPC_FixedUnderlyingType);
      }
    }

    DeclContext *SearchDC = m_Sema->CurContext;
    DeclContext *DC = m_Sema->CurContext;
    //bool isStdBadAlloc = false;
    SourceLocation NameLoc = NewTD->getLocation();
    // if (Name && SS.isNotEmpty()) {
    //   // We have a nested-name tag ('struct foo::bar').

    //   // Check for invalid 'foo::'.
    //   if (SS.isInvalid()) {
    //     Name = 0;
    //     goto CreateNewDecl;
    //   }

    //   // If this is a friend or a reference to a class in a dependent
    //   // context, don't try to make a decl for it.
    //   if (TUK == TUK_Friend || TUK == TUK_Reference) {
    //     DC = computeDeclContext(SS, false);
    //     if (!DC) {
    //       IsDependent = true;
    //       return 0;
    //     }
    //   } else {
    //     DC = computeDeclContext(SS, true);
    //     if (!DC) {
    //       Diag(SS.getRange().getBegin(),
    //            diag::err_dependent_nested_name_spec)
    //         << SS.getRange();
    //       return 0;
    //     }
    //   }

    //   if (RequireCompleteDeclContext(SS, DC))
    //     return 0;

    //   SearchDC = DC;
    //   // Look-up name inside 'foo::'.
    //   LookupQualifiedName(Previous, DC);

    //   if (Previous.isAmbiguous())
    //     return 0;

    //   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.
    //     // But this only makes any sense for reference-like lookups.
    //     if (Previous.wasNotFoundInCurrentInstantiation() &&
    //         (TUK == TUK_Reference || TUK == TUK_Friend)) {
    //       IsDependent = true;
    //       return 0;
    //     }

    //     // A tag 'foo::bar' must already exist.
    //     Diag(NameLoc, diag::err_not_tag_in_scope)
    //       << Kind << Name << DC << SS.getRange();
    //     Name = 0;
    //     Invalid = true;
    //   goto CreateNewDecl;
    // }
    //} else
    if (Name) {
      // If this is a named struct, check to see if there was a previous forward
      // declaration or definition.
      // FIXME: We're looking into outer scopes here, even when we
      // shouldn't be. Doing so can result in ambiguities that we
      // shouldn't be diagnosing.

      //LookupName(Previous, S);

      if (Previous.isAmbiguous()) {
        LookupResult::Filter F = Previous.makeFilter();
        while (F.hasNext()) {
          NamedDecl *ND = F.next();
          if (ND->getDeclContext()->getRedeclContext() != SearchDC)
            F.erase();
        }
        F.done();
      }

      // Note:  there used to be some attempt at recovery here.
      if (Previous.isAmbiguous()) {
        return false;
      }

      if (!m_Sema->getLangOpts().CPlusPlus) {
        // FIXME: This makes sure that we ignore the contexts associated
        // with C structs, unions, and enums when looking for a matching
        // tag declaration or definition. See the similar lookup tweak
        // in Sema::LookupName; is there a better way to deal with this?
        while (isa<RecordDecl>(SearchDC) || isa<EnumDecl>(SearchDC))
          SearchDC = SearchDC->getParent();
      }
    } else if (m_Sema->getScopeForContext(m_Sema->CurContext)
               ->isFunctionPrototypeScope()) {
      // If this is an enum declaration in function prototype scope, set its
      // initial context to the translation unit.
      SearchDC = m_Context->getTranslationUnitDecl();
    }

    if (Previous.isSingleResult() &&
        Previous.getFoundDecl()->isTemplateParameter()) {
      // Maybe we will complain about the shadowed template parameter.
      m_Sema->DiagnoseTemplateParameterShadow(NameLoc, Previous.getFoundDecl());
      // Just pretend that we didn't see the previous declaration.
      Previous.clear();
    }

    if (m_Sema->getLangOpts().CPlusPlus && Name && DC && m_Sema->StdNamespace
        && DC->Equals(m_Sema->getStdNamespace()) && Name->isStr("bad_alloc")) {
      // This is a declaration of or a reference to "std::bad_alloc".
      //isStdBadAlloc = true;

      if (Previous.empty() && m_Sema->StdBadAlloc) {
        // std::bad_alloc has been implicitly declared (but made invisible to
        // name lookup). Fill in this implicit declaration as the previous
        // declaration, so that the declarations get chained appropriately.
        Previous.addDecl(m_Sema->getStdBadAlloc());
      }
    }

    if (!Previous.empty()) {
      NamedDecl *PrevDecl = (*Previous.begin())->getUnderlyingDecl();

      // It's okay to have a tag decl in the same scope as a typedef
      // which hides a tag decl in the same scope.  Finding this
      // insanity with a redeclaration lookup can only actually happen
      // in C++.
      //
      // This is also okay for elaborated-type-specifiers, which is
      // technically forbidden by the current standard but which is
      // okay according to the likely resolution of an open issue;
      // see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#407
      if (m_Sema->getLangOpts().CPlusPlus) {
        if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(PrevDecl)) {
          if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
            TagDecl *Tag = TT->getDecl();
            if (Tag->getDeclName() == Name &&
                Tag->getDeclContext()->getRedeclContext()
                ->Equals(TD->getDeclContext()->getRedeclContext())) {
              PrevDecl = Tag;
              Previous.clear();
              Previous.addDecl(Tag);
              Previous.resolveKind();
            }
          }
        }
      }

      if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) {
        // If this is a use of a previous tag, or if the tag is already declared
        // in the same scope (so that the definition/declaration completes or
        // rementions the tag), reuse the decl.
        if (m_Sema->isDeclInScope(PrevDecl, SearchDC,
                                 m_Sema->getScopeForContext(m_Sema->CurContext),
                                  isExplicitSpecialization)) {
          // Make sure that this wasn't declared as an enum and now used as a
          // struct or something similar.
          SourceLocation KWLoc = NewTD->getLocStart();
          if (!m_Sema->isAcceptableTagRedeclaration(PrevTagDecl, Kind,
                                          NewTD->isThisDeclarationADefinition(),
                                                    KWLoc, *Name)) {
            bool SafeToContinue
              = (PrevTagDecl->getTagKind() != TTK_Enum && Kind != TTK_Enum);

            if (SafeToContinue)
              m_Sema->Diag(KWLoc, diag::err_use_with_wrong_tag)
                << Name
                << FixItHint::CreateReplacement(SourceRange(KWLoc),
                                                PrevTagDecl->getKindName());
            else
              m_Sema->Diag(KWLoc, diag::err_use_with_wrong_tag) << Name;
            m_Sema->Diag(PrevTagDecl->getLocation(), diag::note_previous_use);

            if (SafeToContinue)
              Kind = PrevTagDecl->getTagKind();
            else {
              // Recover by making this an anonymous redefinition.
              Name = 0;
              Previous.clear();
              Invalid = true;
            }
          }

          if (Kind == TTK_Enum && PrevTagDecl->getTagKind() == TTK_Enum) {
            const EnumDecl *NewEnum = cast<EnumDecl>(NewTD);
            const EnumDecl *PrevEnum = cast<EnumDecl>(PrevTagDecl);

            // All conflicts with previous declarations are recovered by
            // returning the previous declaration.
            if (NewEnum->isScoped() != PrevEnum->isScoped()) {
              m_Sema->Diag(KWLoc, diag::err_enum_redeclare_scoped_mismatch)
                << PrevEnum->isScoped();
              m_Sema->Diag(PrevTagDecl->getLocation(), diag::note_previous_use);

              return false;
            }
            else if (PrevEnum->isFixed()) {
              QualType T = NewEnum->getIntegerType();

              if (!m_Context->hasSameUnqualifiedType(T,
                                                  PrevEnum->getIntegerType())) {
                m_Sema->Diag(NameLoc.isValid() ? NameLoc : KWLoc,
                             diag::err_enum_redeclare_type_mismatch)
                  << T
                  << PrevEnum->getIntegerType();
                m_Sema->Diag(PrevTagDecl->getLocation(),
                             diag::note_previous_use);

                return false;
              }
            }
            else if (NewEnum->isFixed() != PrevEnum->isFixed()) {
              m_Sema->Diag(KWLoc, diag::err_enum_redeclare_fixed_mismatch)
                << PrevEnum->isFixed();
              m_Sema->Diag(PrevTagDecl->getLocation(), diag::note_previous_use);

              return false;
            }
          }

          if (!Invalid) {
            // If this is a use, just return the declaration we found.

            // Diagnose attempts to redefine a tag.
            if (NewTD->isThisDeclarationADefinition()) {
              if (TagDecl* Def = PrevTagDecl->getDefinition()) {
                // If we're defining a specialization and the previous
                // definition is from an implicit instantiation, don't emit an
                // error here; we'll catch this in the general case below.
                if (!isExplicitSpecialization ||
                    !isa<CXXRecordDecl>(Def) ||
                    cast<CXXRecordDecl>(Def)->getTemplateSpecializationKind()
                    == TSK_ExplicitSpecialization) {
                  m_Sema->Diag(NameLoc, diag::err_redefinition) << Name;
                  m_Sema->Diag(Def->getLocation(),
                               diag::note_previous_definition);
                  // If this is a redefinition, recover by making this
                  // struct be anonymous, which will make any later
                  // references get the previous definition.
                  Name = 0;
                  Previous.clear();
                  Invalid = true;
                }
              } else {
                // If the type is currently being defined, complain
                // about a nested redefinition.
                const TagType *Tag
                  = cast<TagType>(m_Context->getTagDeclType(PrevTagDecl));
                if (Tag->isBeingDefined()) {
                  m_Sema->Diag(NameLoc, diag::err_nested_redefinition) << Name;
                  m_Sema->Diag(PrevTagDecl->getLocation(),
                               diag::note_previous_definition);
                  Name = 0;
                  Previous.clear();
                  Invalid = true;
                }
              }

              // Okay, this is definition of a previously declared or referenced
              // tag PrevDecl. We're going to create a new Decl for it.
            }
          }
          // If we get here we have (another) forward declaration or we
          // have a definition.  Just create a new decl.

        } else {
          // If we get here, this is a definition of a new tag type in a nested
          // scope, e.g. "struct foo; void bar() { struct foo; }", just create a
          // new decl/type.  We set PrevDecl to NULL so that the entities
          // have distinct types.
          Previous.clear();
        }
        // If we get here, we're going to create a new Decl. If PrevDecl
        // is non-NULL, it's a definition of the tag declared by
        // PrevDecl. If it's NULL, we have a new definition.


        // Otherwise, PrevDecl is not a tag, but was found with tag
        // lookup.  This is only actually possible in C++, where a few
        // things like templates still live in the tag namespace.
      } else {
        assert(m_Sema->getLangOpts().CPlusPlus);

        // Diagnose if the declaration is in scope.
        if (!m_Sema->isDeclInScope(PrevDecl, SearchDC,
                                 m_Sema->getScopeForContext(m_Sema->CurContext),
                                   isExplicitSpecialization)) {
          // do nothing

          // Otherwise it's a declaration.  Call out a particularly common
          // case here.
        } else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(PrevDecl)) {
          unsigned Kind = 0;
          if (isa<TypeAliasDecl>(PrevDecl)) Kind = 1;
          m_Sema->Diag(NameLoc, diag::err_tag_definition_of_typedef)
            << Name << Kind << TND->getUnderlyingType();
          m_Sema->Diag(PrevDecl->getLocation(),
                       diag::note_previous_decl) << PrevDecl;
          Invalid = true;

          // Otherwise, diagnose.
        } else {
          // The tag name clashes with something else in the target scope,
          // issue an error and recover by making this tag be anonymous.
          m_Sema->Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
          m_Sema->Diag(PrevDecl->getLocation(), diag::note_previous_definition);
          Name = 0;
          Invalid = true;
        }

        // The existing declaration isn't relevant to us; we're in a
        // new scope, so clear out the previous declaration.
        Previous.clear();
      }
    }
    if (Invalid) {
      return false;
    }

    return true;
  }
示例#5
0
/// Look up the std::coroutine_traits<...>::promise_type for the given
/// function type.
static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType,
                                  SourceLocation KwLoc,
                                  SourceLocation FuncLoc) {
  // FIXME: Cache std::coroutine_traits once we've found it.
  NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace();
  if (!StdExp) {
    S.Diag(KwLoc, diag::err_implied_coroutine_type_not_found)
        << "std::experimental::coroutine_traits";
    return QualType();
  }

  LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_traits"),
                      FuncLoc, Sema::LookupOrdinaryName);
  if (!S.LookupQualifiedName(Result, StdExp)) {
    S.Diag(KwLoc, diag::err_implied_coroutine_type_not_found)
        << "std::experimental::coroutine_traits";
    return QualType();
  }

  ClassTemplateDecl *CoroTraits = Result.getAsSingle<ClassTemplateDecl>();
  if (!CoroTraits) {
    Result.suppressDiagnostics();
    // We found something weird. Complain about the first thing we found.
    NamedDecl *Found = *Result.begin();
    S.Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits);
    return QualType();
  }

  // Form template argument list for coroutine_traits<R, P1, P2, ...>.
  TemplateArgumentListInfo Args(KwLoc, KwLoc);
  Args.addArgument(TemplateArgumentLoc(
      TemplateArgument(FnType->getReturnType()),
      S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), KwLoc)));
  // FIXME: If the function is a non-static member function, add the type
  // of the implicit object parameter before the formal parameters.
  for (QualType T : FnType->getParamTypes())
    Args.addArgument(TemplateArgumentLoc(
        TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, KwLoc)));

  // Build the template-id.
  QualType CoroTrait =
      S.CheckTemplateIdType(TemplateName(CoroTraits), KwLoc, Args);
  if (CoroTrait.isNull())
    return QualType();
  if (S.RequireCompleteType(KwLoc, CoroTrait,
                            diag::err_coroutine_type_missing_specialization))
    return QualType();

  auto *RD = CoroTrait->getAsCXXRecordDecl();
  assert(RD && "specialization of class template is not a class?");

  // Look up the ::promise_type member.
  LookupResult R(S, &S.PP.getIdentifierTable().get("promise_type"), KwLoc,
                 Sema::LookupOrdinaryName);
  S.LookupQualifiedName(R, RD);
  auto *Promise = R.getAsSingle<TypeDecl>();
  if (!Promise) {
    S.Diag(FuncLoc,
           diag::err_implied_std_coroutine_traits_promise_type_not_found)
        << RD;
    return QualType();
  }
  // The promise type is required to be a class type.
  QualType PromiseType = S.Context.getTypeDeclType(Promise);

  auto buildElaboratedType = [&]() {
    auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, StdExp);
    NNS = NestedNameSpecifier::Create(S.Context, NNS, false,
                                      CoroTrait.getTypePtr());
    return S.Context.getElaboratedType(ETK_None, NNS, PromiseType);
  };

  if (!PromiseType->getAsCXXRecordDecl()) {
    S.Diag(FuncLoc,
           diag::err_implied_std_coroutine_traits_promise_type_not_class)
        << buildElaboratedType();
    return QualType();
  }
  if (S.RequireCompleteType(FuncLoc, buildElaboratedType(),
                            diag::err_coroutine_promise_type_incomplete))
    return QualType();

  return PromiseType;
}
示例#6
0
Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
                                               IdentifierInfo *Name,
                                               SourceLocation NameLoc,
                                               bool IsSuper,
                                               bool HasTrailingDot,
                                               ParsedType &ReceiverType) {
  ReceiverType = ParsedType();

  // If the identifier is "super" and there is no trailing dot, we're
  // messaging super. If the identifier is "super" and there is a
  // trailing dot, it's an instance message.
  if (IsSuper && S->isInObjcMethodScope())
    return HasTrailingDot? ObjCInstanceMessage : ObjCSuperMessage;
  
  LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
  LookupName(Result, S);
  
  switch (Result.getResultKind()) {
  case LookupResult::NotFound:
    // Normal name lookup didn't find anything. If we're in an
    // Objective-C method, look for ivars. If we find one, we're done!
    // FIXME: This is a hack. Ivar lookup should be part of normal
    // lookup.
    if (ObjCMethodDecl *Method = getCurMethodDecl()) {
      ObjCInterfaceDecl *ClassDeclared;
      if (Method->getClassInterface()->lookupInstanceVariable(Name, 
                                                              ClassDeclared))
        return ObjCInstanceMessage;
    }
  
    // Break out; we'll perform typo correction below.
    break;

  case LookupResult::NotFoundInCurrentInstantiation:
  case LookupResult::FoundOverloaded:
  case LookupResult::FoundUnresolvedValue:
  case LookupResult::Ambiguous:
    Result.suppressDiagnostics();
    return ObjCInstanceMessage;

  case LookupResult::Found: {
    // If the identifier is a class or not, and there is a trailing dot,
    // it's an instance message.
    if (HasTrailingDot)
      return ObjCInstanceMessage;
    // We found something. If it's a type, then we have a class
    // message. Otherwise, it's an instance message.
    NamedDecl *ND = Result.getFoundDecl();
    QualType T;
    if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND))
      T = Context.getObjCInterfaceType(Class);
    else if (TypeDecl *Type = dyn_cast<TypeDecl>(ND))
      T = Context.getTypeDeclType(Type);
    else 
      return ObjCInstanceMessage;

    //  We have a class message, and T is the type we're
    //  messaging. Build source-location information for it.
    TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
    ReceiverType = CreateParsedType(T, TSInfo);
    return ObjCClassMessage;
  }
  }

  // Determine our typo-correction context.
  CorrectTypoContext CTC = CTC_Expression;
  if (ObjCMethodDecl *Method = getCurMethodDecl())
    if (Method->getClassInterface() &&
        Method->getClassInterface()->getSuperClass())
      CTC = CTC_ObjCMessageReceiver;
      
  if (DeclarationName Corrected = CorrectTypo(Result, S, 0, 0, false, CTC)) {
    if (Result.isSingleResult()) {
      // If we found a declaration, correct when it refers to an Objective-C
      // class.
      NamedDecl *ND = Result.getFoundDecl();
      if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND)) {
        Diag(NameLoc, diag::err_unknown_receiver_suggest)
          << Name << Result.getLookupName()
          << FixItHint::CreateReplacement(SourceRange(NameLoc),
                                          ND->getNameAsString());
        Diag(ND->getLocation(), diag::note_previous_decl)
          << Corrected;

        QualType T = Context.getObjCInterfaceType(Class);
        TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
        ReceiverType = CreateParsedType(T, TSInfo);
        return ObjCClassMessage;
      }
    } else if (Result.empty() && Corrected.getAsIdentifierInfo() &&
               Corrected.getAsIdentifierInfo()->isStr("super")) {
      // If we've found the keyword "super", this is a send to super.
      Diag(NameLoc, diag::err_unknown_receiver_suggest)
        << Name << Corrected
        << FixItHint::CreateReplacement(SourceRange(NameLoc), "super");
      return ObjCSuperMessage;
    }
  }
  
  // Fall back: let the parser try to parse it as an instance message.
  return ObjCInstanceMessage;
}
示例#7
0
/// Diagnose the path which caused the given declaration or base class
/// to become inaccessible.
static void DiagnoseAccessPath(Sema &S,
                               const EffectiveContext &EC,
                               AccessTarget &Entity) {
  AccessSpecifier Access = Entity.getAccess();
  const CXXRecordDecl *NamingClass = Entity.getNamingClass();
  NamingClass = NamingClass->getCanonicalDecl();

  NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0);
  const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();

  // Easy case: the decl's natural access determined its path access.
  // We have to check against AS_private here in case Access is AS_none,
  // indicating a non-public member of a private base class.
  if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
    switch (HasAccess(S, EC, DeclaringClass, D->getAccess(), Entity)) {
    case AR_inaccessible: {
      S.Diag(D->getLocation(), diag::note_access_natural)
        << (unsigned) (Access == AS_protected)
        << /*FIXME: not implicitly*/ 0;
      return;
    }

    case AR_accessible: break;

    case AR_dependent:
      llvm_unreachable("can't diagnose dependent access failures");
      return;
    }
  }

  CXXBasePaths Paths;
  CXXBasePath &Path = *FindBestPath(S, EC, Entity, AS_public, Paths);

  CXXBasePath::iterator I = Path.end(), E = Path.begin();
  while (I != E) {
    --I;

    const CXXBaseSpecifier *BS = I->Base;
    AccessSpecifier BaseAccess = BS->getAccessSpecifier();

    // If this is public inheritance, or the derived class is a friend,
    // skip this step.
    if (BaseAccess == AS_public)
      continue;

    switch (GetFriendKind(S, EC, I->Class)) {
    case AR_accessible: continue;
    case AR_inaccessible: break;
    case AR_dependent:
      llvm_unreachable("can't diagnose dependent access failures");
    }

    // Check whether this base specifier is the tighest point
    // constraining access.  We have to check against AS_private for
    // the same reasons as above.
    if (BaseAccess == AS_private || BaseAccess >= Access) {

      // We're constrained by inheritance, but we want to say
      // "declared private here" if we're diagnosing a hierarchy
      // conversion and this is the final step.
      unsigned diagnostic;
      if (D) diagnostic = diag::note_access_constrained_by_path;
      else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural;
      else diagnostic = diag::note_access_constrained_by_path;

      S.Diag(BS->getSourceRange().getBegin(), diagnostic)
        << BS->getSourceRange()
        << (BaseAccess == AS_protected)
        << (BS->getAccessSpecifierAsWritten() == AS_none);
      return;
    }
  }

  llvm_unreachable("access not apparently constrained by path");
}
NamespaceDecl *Sema::ActOnRogerNamespaceHeaderPart(DeclContext *DeclContext, IdentifierInfo *II,
        SourceLocation IdentLoc,
        AttributeList *AttrList) {
    // set CurContext

    SourceLocation NamespaceLoc;
    SourceLocation InlineLoc;
    SourceLocation StartLoc = InlineLoc.isValid() ? InlineLoc : NamespaceLoc;

    assert(II);
    SourceLocation Loc = IdentLoc;
    bool IsInline = false;
    bool IsInvalid = false;
    bool IsStd = false;
    bool AddToKnown = false;
    //Scope *DeclRegionScope = NamespcScope->getParent();

    NamespaceDecl *PrevNS = 0;
    // C++ [namespace.def]p2:
    //   The identifier in an original-namespace-definition shall not
    //   have been previously defined in the declarative region in
    //   which the original-namespace-definition appears. The
    //   identifier in an original-namespace-definition is the name of
    //   the namespace. Subsequently in that declarative region, it is
    //   treated as an original-namespace-name.
    //
    // Since namespace names are unique in their scope, and we don't
    // look through using directives, just look for any ordinary names.

    const unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Member |
                          Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag |
                          Decl::IDNS_Namespace;
    NamedDecl *PrevDecl = 0;
    DeclContext::lookup_result R = DeclContext->getRedeclContext()->lookup(II);
    for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
            ++I) {
        if ((*I)->getIdentifierNamespace() & IDNS) {
            PrevDecl = *I;
            break;
        }
    }

    PrevNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl);

    if (PrevNS) {
        // This is an extended namespace definition.
        if (IsInline != PrevNS->isInline()) {
//      DiagnoseNamespaceInlineMismatch(*this, NamespaceLoc, Loc, II,
//                                      &IsInline, PrevNS);
            assert(false && "need to implement this");
        }
        return PrevNS;
    } else if (PrevDecl) {
        // This is an invalid name redefinition.
        Diag(Loc, diag::err_redefinition_different_kind)
                << II;
        Diag(PrevDecl->getLocation(), diag::note_previous_definition);
        IsInvalid = true;
        // Continue on to push Namespc as current DeclContext and return it.
    } else if (II->isStr("std") &&
               DeclContext->getRedeclContext()->isTranslationUnit()) {
        // This is the first "real" definition of the namespace "std", so update
        // our cache of the "std" namespace to point at this definition.
        PrevNS = getStdNamespace();
        IsStd = true;
        AddToKnown = !IsInline;
    } else {
        // We've seen this namespace for the first time.
        AddToKnown = !IsInline;
    }

    NamespaceDecl *Namespc = NamespaceDecl::Create(Context, DeclContext, IsInline,
                             StartLoc, Loc, II, PrevNS);
    Namespc->IsRogerNamespace = true;

    if (IsInvalid)
        Namespc->setInvalidDecl();

    //ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);

    // FIXME: Should we be merging attributes?
    if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
        PushNamespaceVisibilityAttr(Attr, Loc);

    if (IsStd)
        StdNamespace = Namespc;
    if (AddToKnown)
        KnownNamespaces[Namespc] = false;

    DeclContext->addDecl(Namespc);

    if (PrevNS) {
        return PrevNS;
    } else {
        return Namespc;
    }
}
示例#9
0
/// \brief Build a new nested-name-specifier for "identifier::", as described
/// by ActOnCXXNestedNameSpecifier.
///
/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
/// that it contains an extra parameter \p ScopeLookupResult, which provides
/// the result of name lookup within the scope of the nested-name-specifier
/// that was computed at template definition time.
///
/// If ErrorRecoveryLookup is true, then this call is used to improve error
/// recovery.  This means that it should not emit diagnostics, it should
/// just return null on failure.  It also means it should only return a valid
/// scope if it *knows* that the result is correct.  It should not return in a
/// dependent context, for example.
Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
                                                    const CXXScopeSpec &SS,
                                                    SourceLocation IdLoc,
                                                    SourceLocation CCLoc,
                                                    IdentifierInfo &II,
                                                    QualType ObjectType,
                                                  NamedDecl *ScopeLookupResult,
                                                    bool EnteringContext,
                                                    bool ErrorRecoveryLookup) {
  NestedNameSpecifier *Prefix
    = static_cast<NestedNameSpecifier *>(SS.getScopeRep());

  LookupResult Found(*this, &II, IdLoc, LookupNestedNameSpecifierName);

  // Determine where to perform name lookup
  DeclContext *LookupCtx = 0;
  bool isDependent = false;
  if (!ObjectType.isNull()) {
    // This nested-name-specifier occurs in a member access expression, e.g.,
    // x->B::f, and we are looking into the type of the object.
    assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
    LookupCtx = computeDeclContext(ObjectType);
    isDependent = ObjectType->isDependentType();
  } else if (SS.isSet()) {
    // This nested-name-specifier occurs after another nested-name-specifier,
    // so long into the context associated with the prior nested-name-specifier.
    LookupCtx = computeDeclContext(SS, EnteringContext);
    isDependent = isDependentScopeSpecifier(SS);
    Found.setContextRange(SS.getRange());
  }


  bool ObjectTypeSearchedInScope = false;
  if (LookupCtx) {
    // Perform "qualified" name lookup into the declaration context we
    // computed, which is either the type of the base of a member access
    // expression or the declaration context associated with a prior
    // nested-name-specifier.

    // The declaration context must be complete.
    if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS))
      return 0;

    LookupQualifiedName(Found, LookupCtx);

    if (!ObjectType.isNull() && Found.empty()) {
      // C++ [basic.lookup.classref]p4:
      //   If the id-expression in a class member access is a qualified-id of
      //   the form
      //
      //        class-name-or-namespace-name::...
      //
      //   the class-name-or-namespace-name following the . or -> operator is
      //   looked up both in the context of the entire postfix-expression and in
      //   the scope of the class of the object expression. If the name is found
      //   only in the scope of the class of the object expression, the name
      //   shall refer to a class-name. If the name is found only in the
      //   context of the entire postfix-expression, the name shall refer to a
      //   class-name or namespace-name. [...]
      //
      // Qualified name lookup into a class will not find a namespace-name,
      // so we do not need to diagnoste that case specifically. However,
      // this qualified name lookup may find nothing. In that case, perform
      // unqualified name lookup in the given scope (if available) or
      // reconstruct the result from when name lookup was performed at template
      // definition time.
      if (S)
        LookupName(Found, S);
      else if (ScopeLookupResult)
        Found.addDecl(ScopeLookupResult);

      ObjectTypeSearchedInScope = true;
    }
  } else if (isDependent) {
    // Don't speculate if we're just trying to improve error recovery.
    if (ErrorRecoveryLookup)
      return 0;
    
    // We were not able to compute the declaration context for a dependent
    // base object type or prior nested-name-specifier, so this
    // nested-name-specifier refers to an unknown specialization. Just build
    // a dependent nested-name-specifier.
    if (!Prefix)
      return NestedNameSpecifier::Create(Context, &II);

    return NestedNameSpecifier::Create(Context, Prefix, &II);
  } else {
    // Perform unqualified name lookup in the current scope.
    LookupName(Found, S);
  }

  // FIXME: Deal with ambiguities cleanly.

  if (Found.empty() && !ErrorRecoveryLookup) {
    // We haven't found anything, and we're not recovering from a
    // different kind of error, so look for typos.
    DeclarationName Name = Found.getLookupName();
    if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext) &&
        Found.isSingleResult() &&
        isAcceptableNestedNameSpecifier(Found.getAsSingle<NamedDecl>())) {
      if (LookupCtx)
        Diag(Found.getNameLoc(), diag::err_no_member_suggest)
          << Name << LookupCtx << Found.getLookupName() << SS.getRange()
          << CodeModificationHint::CreateReplacement(Found.getNameLoc(),
                                           Found.getLookupName().getAsString());
      else
        Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest)
          << Name << Found.getLookupName()
          << CodeModificationHint::CreateReplacement(Found.getNameLoc(),
                                           Found.getLookupName().getAsString());
      
      if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
        Diag(ND->getLocation(), diag::note_previous_decl)
          << ND->getDeclName();
    } else
      Found.clear();
  }

  NamedDecl *SD = Found.getAsSingle<NamedDecl>();
  if (isAcceptableNestedNameSpecifier(SD)) {
    if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) {
      // C++ [basic.lookup.classref]p4:
      //   [...] If the name is found in both contexts, the
      //   class-name-or-namespace-name shall refer to the same entity.
      //
      // We already found the name in the scope of the object. Now, look
      // into the current scope (the scope of the postfix-expression) to
      // see if we can find the same name there. As above, if there is no
      // scope, reconstruct the result from the template instantiation itself.
      NamedDecl *OuterDecl;
      if (S) {
        LookupResult FoundOuter(*this, &II, IdLoc, LookupNestedNameSpecifierName);
        LookupName(FoundOuter, S);
        OuterDecl = FoundOuter.getAsSingle<NamedDecl>();
      } else
        OuterDecl = ScopeLookupResult;

      if (isAcceptableNestedNameSpecifier(OuterDecl) &&
          OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() &&
          (!isa<TypeDecl>(OuterDecl) || !isa<TypeDecl>(SD) ||
           !Context.hasSameType(
                            Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)),
                               Context.getTypeDeclType(cast<TypeDecl>(SD))))) {
             if (ErrorRecoveryLookup)
               return 0;
             
             Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous)
               << &II;
             Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type)
               << ObjectType;
             Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope);

             // Fall through so that we'll pick the name we found in the object
             // type, since that's probably what the user wanted anyway.
           }
    }

    if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD))
      return NestedNameSpecifier::Create(Context, Prefix, Namespace);

    // FIXME: It would be nice to maintain the namespace alias name, then
    // see through that alias when resolving the nested-name-specifier down to
    // a declaration context.
    if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD))
      return NestedNameSpecifier::Create(Context, Prefix,

                                         Alias->getNamespace());

    QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
    return NestedNameSpecifier::Create(Context, Prefix, false,
                                       T.getTypePtr());
  }

  // Otherwise, we have an error case.  If we don't want diagnostics, just
  // return an error now.
  if (ErrorRecoveryLookup)
    return 0;

  // If we didn't find anything during our lookup, try again with
  // ordinary name lookup, which can help us produce better error
  // messages.
  if (Found.empty()) {
    Found.clear(LookupOrdinaryName);
    LookupName(Found, S);
  }

  unsigned DiagID;
  if (!Found.empty())
    DiagID = diag::err_expected_class_or_namespace;
  else if (SS.isSet()) {
    Diag(IdLoc, diag::err_no_member) << &II << LookupCtx << SS.getRange();
    return 0;
  } else
    DiagID = diag::err_undeclared_var_use;

  if (SS.isSet())
    Diag(IdLoc, DiagID) << &II << SS.getRange();
  else
    Diag(IdLoc, DiagID) << &II;

  return 0;
}
示例#10
0
Action::OwningExprResult
Sema::BuildMemberReferenceExpr(Expr *BaseExpr, const Type *BaseExprType,
                               SourceLocation OpLoc, LookupResult &R) {
  const Type* BaseType = BaseExprType;

  if (const PointerType *P = dyn_cast<PointerType>(BaseType))
    BaseType = P->getPointeeType();
  //R.setBaseObjectType(BaseType);

  //const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo();
  //DeclarationName MemberName = MemberNameInfo.getName();
  //SourceLocation MemberLoc = MemberNameInfo.getLoc();
  IdentifierInfo *II = R.getLookupName();

  if (R.isAmbiguous())
    return ExprError();

  if (R.empty()) {
    // FIXME: make sure this prints the '*' for pointer-to-struct types (?)
    //DeclContext *DC = BaseType->getAs<StructType>()->getDecl();
    // FIXME: clang prints DC instead of BaseExprType here. Don't do that,
    // else we don't print struct names right. However, make sure ParenTypes
    // get desugared once they exist.
    Diag(R.getNameLoc(), diag::no_field) << II << BaseExprType;
    //Diag(R.getNameLoc(), diag::err_no_member)
      //<< MemberName << DC
      //<< (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
    return ExprError();
  }

  assert(R.isSingleResult());
  NamedDecl *MemberDecl = R.getFoundDecl();
#if 0
  DeclAccessPair FoundDecl = R.begin().getPair();

  // If the decl being referenced had an error, return an error for this
  // sub-expr without emitting another error, in order to avoid cascading
  // error cases.
  if (MemberDecl->isInvalidDecl())
    return ExprError();

  bool ShouldCheckUse = true;
  if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) {
    // Don't diagnose the use of a virtual member function unless it's
    // explicitly qualified.
    if (MD->isVirtual())
      ShouldCheckUse = false;
  }

  // Check the use of this member.
  if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) {
    Owned(BaseExpr);
    return ExprError();
  }
#endif

  if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) {
    //return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow,
                                   //FD, FoundDecl, MemberNameInfo);
    return Owned(BuildMemberExpr(*this, Context, BaseExpr, FD,
                                 R.getNameLoc(), FD->getType()));
  }

#if 0
  if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl))
    // We may have found a field within an anonymous union or struct
    // (C++ [class.union]).
    return BuildAnonymousStructUnionMemberReference(MemberLoc, FD,
                                                    BaseExpr, OpLoc);

  if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
    return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow,
                                 Var, FoundDecl, MemberNameInfo,
                                 Var->getType().getNonReferenceType(),
                                 VK_LValue, OK_Ordinary));
  }

  if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) {
    ExprValueKind valueKind;
    QualType type;
    if (MemberFn->isInstance()) {
      valueKind = VK_RValue;
      type = Context.BoundMemberTy;
    } else {
      valueKind = VK_LValue;
      type = MemberFn->getType();
    }

    return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow,
                                 MemberFn, FoundDecl, 
                                 MemberNameInfo, type, valueKind,
                                 OK_Ordinary));
  }
  assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");

  if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
    return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow,
                                 Enum, FoundDecl, MemberNameInfo,
                                 Enum->getType(), VK_RValue, OK_Ordinary));
  }

  Owned(BaseExpr);

  // We found something that we didn't expect. Complain.
  if (isa<TypeDecl>(MemberDecl))
    Diag(MemberLoc, diag::err_typecheck_member_reference_type)
      << MemberName << BaseType << int(IsArrow);
  else
    Diag(MemberLoc, diag::err_typecheck_member_reference_unknown)
      << MemberName << BaseType << int(IsArrow);

  Diag(MemberDecl->getLocation(), diag::note_member_declared_here)
    << MemberName;
  R.suppressDiagnostics();
#endif
  return ExprError();
}