Exemplo n.º 1
0
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
/// scope or nested-name-specifier) is parsed, part of a declarator-id.
/// After this method is called, according to [C++ 3.4.3p3], names should be
/// looked up in the declarator-id's scope, until the declarator is parsed and
/// ActOnCXXExitDeclaratorScope is called.
/// The 'SS' should be a non-empty valid CXXScopeSpec.
bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS) {
  assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");

  if (SS.isInvalid()) return true;

  DeclContext *DC = computeDeclContext(SS, true);
  if (!DC) return true;

  // Before we enter a declarator's context, we need to make sure that
  // it is a complete declaration context.
  if (!DC->isDependentContext() && RequireCompleteDeclContext(SS, DC))
    return true;

  EnterDeclaratorContext(S, DC);

  // Rebuild the nested name specifier for the new scope.
  if (DC->isDependentContext())
    RebuildNestedNameSpecifierInCurrentInstantiation(SS);

  return false;
}
Exemplo n.º 2
0
/// Ensure that the outer generic parameters of the given generic
/// context have been configured.
static void configureOuterGenericParams(const GenericContext *dc) {
  auto genericParams = dc->getGenericParams();

  // If we already configured the outer parameters, we're done.
  if (genericParams && genericParams->getOuterParameters())
    return;

  DeclContext *outerDC = dc->getParent();
  while (!outerDC->isModuleScopeContext()) {
    if (auto outerDecl = outerDC->getAsDecl()) {
      if (auto outerGenericDC = outerDecl->getAsGenericContext()) {
        if (genericParams)
          genericParams->setOuterParameters(outerGenericDC->getGenericParams());

        configureOuterGenericParams(outerGenericDC);
        return;
      }
    }

    outerDC = outerDC->getParent();
  }
}
Exemplo n.º 3
0
DeclContext *DeclContext::getInnermostTypeContext() {
  DeclContext *Result = this;
  while (true) {
    switch (Result->getContextKind()) {
    case DeclContextKind::AbstractClosureExpr:
    case DeclContextKind::Initializer:
    case DeclContextKind::TopLevelCodeDecl:
    case DeclContextKind::AbstractFunctionDecl:
    case DeclContextKind::SerializedLocal:
      Result = Result->getParent();
      continue;

    case DeclContextKind::Module:
    case DeclContextKind::FileUnit:
      return nullptr;

    case DeclContextKind::ExtensionDecl:
    case DeclContextKind::NominalTypeDecl:
      return Result;
    }
  }
}
Exemplo n.º 4
0
DeclContext::lookup_result
DeclContext::noload_lookup(DeclarationName Name) {
  assert(DeclKind != Decl::LinkageSpec &&
         "Should not perform lookups into linkage specs!");
  if (!hasExternalVisibleStorage())
    return lookup(Name);

  DeclContext *PrimaryContext = getPrimaryContext();
  if (PrimaryContext != this)
    return PrimaryContext->noload_lookup(Name);

  StoredDeclsMap *Map = LookupPtr.getPointer();
  if (LookupPtr.getInt()) {
    // Carefully build the lookup map, without deserializing anything.
    SmallVector<DeclContext *, 2> Contexts;
    collectAllContexts(Contexts);
    for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
      buildLookupImpl<&DeclContext::noload_decls_begin,
                      &DeclContext::noload_decls_end>(Contexts[I]);

    // We no longer have any lazy decls.
    LookupPtr.setInt(false);

    // There may now be names for which we have local decls but are
    // missing the external decls. FIXME: Just set the hasExternalDecls
    // flag on those names that have external decls.
    NeedToReconcileExternalVisibleStorage = true;

    Map = LookupPtr.getPointer();
  }

  if (!Map)
    return lookup_result(lookup_iterator(0), lookup_iterator(0));

  StoredDeclsMap::iterator I = Map->find(Name);
  return I != Map->end()
             ? I->second.getLookupResult()
             : lookup_result(lookup_iterator(0), lookup_iterator(0));
}
Exemplo n.º 5
0
static void GCRewriteFinalize(MigrationPass &pass) {
  ASTContext &Ctx = pass.Ctx;
  TransformActions &TA = pass.TA;
  DeclContext *DC = Ctx.getTranslationUnitDecl();
  Selector FinalizeSel =
   Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));

  typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
  impl_iterator;
  for (impl_iterator I = impl_iterator(DC->decls_begin()),
       E = impl_iterator(DC->decls_end()); I != E; ++I) {
    for (ObjCImplementationDecl::instmeth_iterator
         MI = I->instmeth_begin(),
         ME = I->instmeth_end(); MI != ME; ++MI) {
      ObjCMethodDecl *MD = *MI;
      if (!MD->hasBody())
        continue;

      if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
        ObjCMethodDecl *FinalizeM = MD;
        Transaction Trans(TA);
        TA.insert(FinalizeM->getSourceRange().getBegin(),
                  "#if !__has_feature(objc_arc)\n");
        CharSourceRange::getTokenRange(FinalizeM->getSourceRange());
        const SourceManager &SM = pass.Ctx.getSourceManager();
        const LangOptions &LangOpts = pass.Ctx.getLangOpts();
        bool Invalid;
        std::string str = "\n#endif\n";
        str += Lexer::getSourceText(
                  CharSourceRange::getTokenRange(FinalizeM->getSourceRange()),
                                    SM, LangOpts, &Invalid);
        TA.insertAfterToken(FinalizeM->getSourceRange().getEnd(), str);

        break;
      }
    }
  }
}
Exemplo n.º 6
0
static SILFunction::ClassVisibility_t getClassVisibility(SILDeclRef constant) {
  if (!constant.hasDecl())
    return SILFunction::NotRelevant;

  // If this declaration is a function which goes into a vtable, then it's
  // symbol must be as visible as its class. Derived classes even have to put
  // all less visible methods of the base class into their vtables.

  auto *FD = dyn_cast<AbstractFunctionDecl>(constant.getDecl());
  if (!FD)
    return SILFunction::NotRelevant;

  DeclContext *context = FD->getDeclContext();

  // Methods from extensions don't go into vtables (yet).
  if (context->isExtensionContext())
    return SILFunction::NotRelevant;

  auto *classType = context->getAsClassOrClassExtensionContext();
  if (!classType || classType->isFinal())
    return SILFunction::NotRelevant;

  if (FD->isFinal() && !FD->getOverriddenDecl())
    return SILFunction::NotRelevant;

  assert(FD->getEffectiveAccess() <= classType->getEffectiveAccess() &&
         "class must be as visible as its members");

  switch (classType->getEffectiveAccess()) {
    case Accessibility::Private:
    case Accessibility::FilePrivate:
      return SILFunction::NotRelevant;
    case Accessibility::Internal:
      return SILFunction::InternalClass;
    case Accessibility::Public:
      return SILFunction::PublicClass;
  }
}
Exemplo n.º 7
0
DeclContext::lookup_result
DeclContext::lookup(DeclarationName Name) {
  assert(DeclKind != Decl::LinkageSpec &&
         "Should not perform lookups into linkage specs!");

  DeclContext *PrimaryContext = getPrimaryContext();
  if (PrimaryContext != this)
    return PrimaryContext->lookup(Name);

  if (hasExternalVisibleStorage()) {
    // If a PCH has a result for this name, and we have a local declaration, we
    // will have imported the PCH result when adding the local declaration.
    // FIXME: For modules, we could have had more declarations added by module
    // imoprts since we saw the declaration of the local name.
    if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
      StoredDeclsMap::iterator I = Map->find(Name);
      if (I != Map->end())
        return I->second.getLookupResult();
    }

    ExternalASTSource *Source = getParentASTContext().getExternalSource();
    return Source->FindExternalVisibleDeclsByName(this, Name);
  }

  StoredDeclsMap *Map = LookupPtr.getPointer();
  if (LookupPtr.getInt())
    Map = buildLookup();

  if (!Map)
    return lookup_result(lookup_iterator(0), lookup_iterator(0));

  StoredDeclsMap::iterator I = Map->find(Name);
  if (I == Map->end())
    return lookup_result(lookup_iterator(0), lookup_iterator(0));

  return I->second.getLookupResult();
}
static void removeDeallocMethod(MigrationPass &pass) {
  ASTContext &Ctx = pass.Ctx;
  TransformActions &TA = pass.TA;
  DeclContext *DC = Ctx.getTranslationUnitDecl();

  typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
    impl_iterator;
  for (impl_iterator I = impl_iterator(DC->decls_begin()),
                     E = impl_iterator(DC->decls_end()); I != E; ++I) {
    for (ObjCImplementationDecl::instmeth_iterator
           MI = (*I)->instmeth_begin(),
           ME = (*I)->instmeth_end(); MI != ME; ++MI) {
      ObjCMethodDecl *MD = *MI;
      if (MD->getMethodFamily() == OMF_dealloc) {
        if (MD->hasBody() &&
            isBodyEmpty(MD->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) {
          Transaction Trans(TA);
          TA.remove(MD->getSourceRange());
        }
        break;
      }
    }
  }
}
Exemplo n.º 9
0
void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) {
  // FIXME: This feels like a hack. Should DeclarationName support
  // template-ids, or is there a better way to keep specializations
  // from being visible?
  if (isa<ClassTemplateSpecializationDecl>(D))
    return;

  DeclContext *PrimaryContext = getPrimaryContext();
  if (PrimaryContext != this) {
    PrimaryContext->makeDeclVisibleInContext(D, Recoverable);
    return;
  }

  // If we already have a lookup data structure, perform the insertion
  // into it. Otherwise, be lazy and don't build that structure until
  // someone asks for it.
  if (LookupPtr || !Recoverable)
    makeDeclVisibleInContextImpl(D);

  // If we are a transparent context, insert into our parent context,
  // too. This operation is recursive.
  if (isTransparentContext())
    getParent()->makeDeclVisibleInContext(D, Recoverable);
}
Exemplo n.º 10
0
bool ClassTemplateToClass::hasUsedNameDecl(
       ClassTemplatePartialSpecializationDecl *PartialD)
{
  if (!PartialD->isCompleteDefinition())
    return false;

  SmallPtrSet<NamedDecl *, 8> Params;
  TemplateParameterList *PartialTPList = PartialD->getTemplateParameters();
  for (unsigned PI = 0; PI < PartialTPList->size(); ++PI) {
    NamedDecl *ND = PartialTPList->getParam(PI);
    if (dyn_cast<NonTypeTemplateParmDecl>(ND))
      continue;
    Params.insert(ND);  
  }

  TemplateParameterTypeVisitor ParamVisitor(Context);

  // Skip visiting parameters and arguments
  for (CXXRecordDecl::base_class_iterator I = PartialD->bases_begin(),
       E = PartialD->bases_end(); I != E; ++I) {
    ParamVisitor.TraverseType(I->getType());
  }

  DeclContext *Ctx = dyn_cast<DeclContext>(PartialD);
  for (DeclContext::decl_iterator DI = Ctx->decls_begin(), 
       DE = Ctx->decls_end(); DI != DE; ++DI) {
    ParamVisitor.TraverseDecl(*DI);
  }

  for (SmallPtrSet<NamedDecl *, 8>::iterator I = Params.begin(), 
       E = Params.end(); I != E; ++I) {
    if (ParamVisitor.isAUsedParameter(*I))
      return true;
  }
  return false;
}
Exemplo n.º 11
0
DeclContext::lookup_result
DeclContext::lookup(IdentifierInfo &Name) {
  DeclContext *PrimaryContext = getPrimaryContext();
  if (PrimaryContext != this)  // FIXME: not needed?
    return PrimaryContext->lookup(Name);

#if 0  // FIXME: modules. eventually. resync this part from clang.
  if (hasExternalVisibleStorage()) {
    // If a PCH has a result for this name, and we have a local declaration, we
    // will have imported the PCH result when adding the local declaration.
    // FIXME: For modules, we could have had more declarations added by module
    // imoprts since we saw the declaration of the local name.
    if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
      StoredDeclsMap::iterator I = Map->find(&Name);
      if (I != Map->end())
        return I->second.getLookupResult();
    }

    ExternalASTSource *Source = getParentASTContext().getExternalSource();
    return Source->FindExternalVisibleDeclsByName(this, Name);
  }
#endif

  StoredDeclsMap *Map = LookupPtr.getPointer();
  if (LookupPtr.getInt())
    Map = buildLookup();

  if (!Map)
    return lookup_result(lookup_iterator(0), lookup_iterator(0));

  StoredDeclsMap::iterator I = Map->find(&Name);
  if (I == Map->end())
    return lookup_result(lookup_iterator(0), lookup_iterator(0));

  return I->second.getLookupResult();
}
Exemplo n.º 12
0
 bool mismatch(SubstitutableType *paramType, TypeBase *argType,
               Type sugaredFirstType) {
   Type type = paramType;
   if (type->is<GenericTypeParamType>()) {
     assert(dc);
     type = dc->mapTypeIntoContext(paramType);
   }
   
   if (auto archetype = type->getAs<ArchetypeType>()) {
     auto existing = archetypesMap[archetype];
     if (existing)
       return existing->isEqual(argType);
     archetypesMap[archetype] = argType;
     return true;
   }
   return false;
 }
Exemplo n.º 13
0
CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange,
                                             bool KnownDependent) {
  DeclContext *DC = CurContext;
  while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
    DC = DC->getParent();
  
  // Start constructing the lambda class.
  CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC, 
                                                     IntroducerRange.getBegin(),
                                                     KnownDependent);
  DC->addDecl(Class);
  
  return Class;
}
Exemplo n.º 14
0
void clang::FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind, 
                                            intptr_t Val,
                                            const char *Modifier, 
                                            unsigned ModLen,
                                            const char *Argument, 
                                            unsigned ArgLen,
                                    const Diagnostic::ArgumentValue *PrevArgs,
                                            unsigned NumPrevArgs,
                                            llvm::SmallVectorImpl<char> &Output,
                                            void *Cookie) {
  ASTContext &Context = *static_cast<ASTContext*>(Cookie);
  
  std::string S;
  bool NeedQuotes = true;
  
  switch (Kind) {
    default: assert(0 && "unknown ArgumentKind");
    case Diagnostic::ak_qualtype: {
      assert(ModLen == 0 && ArgLen == 0 &&
             "Invalid modifier for QualType argument");
      
      QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
      S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs);
      NeedQuotes = false;
      break;
    }
    case Diagnostic::ak_declarationname: {
      DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
      S = N.getAsString();
      
      if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
        S = '+' + S;
      else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12)
                && ArgLen==0)
        S = '-' + S;
      else
        assert(ModLen == 0 && ArgLen == 0 &&
               "Invalid modifier for DeclarationName argument");
      break;
    }
    case Diagnostic::ak_nameddecl: {
      bool Qualified;
      if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
        Qualified = true;
      else {
        assert(ModLen == 0 && ArgLen == 0 &&
               "Invalid modifier for NamedDecl* argument");
        Qualified = false;
      }
      reinterpret_cast<NamedDecl*>(Val)->
      getNameForDiagnostic(S, Context.PrintingPolicy, Qualified);
      break;
    }
    case Diagnostic::ak_nestednamespec: {
      llvm::raw_string_ostream OS(S);
      reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS,
                                                        Context.PrintingPolicy);
      NeedQuotes = false;
      break;
    }
    case Diagnostic::ak_declcontext: {
      DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
      assert(DC && "Should never have a null declaration context");
      
      if (DC->isTranslationUnit()) {
        // FIXME: Get these strings from some localized place
        if (Context.getLangOptions().CPlusPlus)
          S = "the global namespace";
        else
          S = "the global scope";
      } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
        S = ConvertTypeToDiagnosticString(Context, 
                                          Context.getTypeDeclType(Type),
                                          PrevArgs, NumPrevArgs);
      } else {
        // FIXME: Get these strings from some localized place
        NamedDecl *ND = cast<NamedDecl>(DC);
        if (isa<NamespaceDecl>(ND))
          S += "namespace ";
        else if (isa<ObjCMethodDecl>(ND))
          S += "method ";
        else if (isa<FunctionDecl>(ND))
          S += "function ";
        
        S += "'";
        ND->getNameForDiagnostic(S, Context.PrintingPolicy, true);
        S += "'";
      }
      NeedQuotes = false;
      break;
    }
  }
  
  if (NeedQuotes)
    Output.push_back('\'');
  
  Output.append(S.begin(), S.end());
  
  if (NeedQuotes)
    Output.push_back('\'');
}
Exemplo n.º 15
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;
}
Exemplo n.º 16
0
DeclContext::lookup_result
DeclContext::lookup(DeclarationName Name) {
  assert(DeclKind != Decl::LinkageSpec &&
         "Should not perform lookups into linkage specs!");

  DeclContext *PrimaryContext = getPrimaryContext();
  if (PrimaryContext != this)
    return PrimaryContext->lookup(Name);

#if AXEL_LOOKUP_CHANGES
  StoredDeclsMap *Map = LookupPtr.getPointer();
  if (LookupPtr.getInt())
    Map = buildLookup();
#endif

  if (hasExternalVisibleStorage()) {
    // If a PCH has a result for this name, and we have a local declaration, we
    // will have imported the PCH result when adding the local declaration.
    // FIXME: For modules, we could have had more declarations added by module
    // imoprts since we saw the declaration of the local name.
#if AXEL_LOOKUP_CHANGES
    if (Map) {
#else
    if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
#endif
      StoredDeclsMap::iterator I = Map->find(Name);
      if (I != Map->end())
        return I->second.getLookupResult();
    }

    ExternalASTSource *Source = getParentASTContext().getExternalSource();
    return Source->FindExternalVisibleDeclsByName(this, Name);
  }

#ifndef AXEL_LOOKUP_CHANGES
  StoredDeclsMap *Map = LookupPtr.getPointer();
  if (LookupPtr.getInt())
    Map = buildLookup();
#endif

  if (!Map)
    return lookup_result(lookup_iterator(0), lookup_iterator(0));

  StoredDeclsMap::iterator I = Map->find(Name);
  if (I == Map->end())
    return lookup_result(lookup_iterator(0), lookup_iterator(0));

  return I->second.getLookupResult();
}

void DeclContext::localUncachedLookup(DeclarationName Name, 
                                  llvm::SmallVectorImpl<NamedDecl *> &Results) {
  Results.clear();
  
  // If there's no external storage, just perform a normal lookup and copy
  // the results.
  if (!hasExternalVisibleStorage() && !hasExternalLexicalStorage() && Name) {
    lookup_result LookupResults = lookup(Name);
    Results.insert(Results.end(), LookupResults.first, LookupResults.second);
    return;
  }

  // If we have a lookup table, check there first. Maybe we'll get lucky.
  if (Name) {
    if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
      StoredDeclsMap::iterator Pos = Map->find(Name);
      if (Pos != Map->end()) {
        Results.insert(Results.end(),
                       Pos->second.getLookupResult().first,
                       Pos->second.getLookupResult().second);
        return;
      }
    }
  }

  // Slow case: grovel through the declarations in our chain looking for 
  // matches.
  for (Decl *D = FirstDecl; D; D = D->getNextDeclInContext()) {
    if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
      if (ND->getDeclName() == Name)
        Results.push_back(ND);
  }
}
Exemplo n.º 17
0
/// True if the function should have its body serialized.
IsSerialized_t SILDeclRef::isSerialized() const {
  DeclContext *dc;
  if (auto closure = getAbstractClosureExpr()) {
    dc = closure->getLocalContext();

    // Otherwise, ask the AST if we're inside an @inlinable context.
    if (dc->getResilienceExpansion() == ResilienceExpansion::Minimal) {
      if (isForeign)
        return IsSerializable;

      return IsSerialized;
    }

    return IsNotSerialized;
  }

  if (isIVarInitializerOrDestroyer())
    return IsNotSerialized;

  auto *d = getDecl();

  // Default argument generators are serialized if the containing
  // declaration is public.
  if (isDefaultArgGenerator()) {
    ResilienceExpansion expansion;
    if (auto *EED = dyn_cast<EnumElementDecl>(d)) {
      expansion = EED->getDefaultArgumentResilienceExpansion();
    } else {
      expansion = cast<AbstractFunctionDecl>(d)
                    ->getDefaultArgumentResilienceExpansion();
    }
    switch (expansion) {
    case ResilienceExpansion::Minimal:
      return IsSerialized;
    case ResilienceExpansion::Maximal:
      return IsNotSerialized;
    }
  }

  // Stored property initializers are inlinable if the type is explicitly
  // marked as @_fixed_layout.
  if (isStoredPropertyInitializer()) {
    auto *nominal = cast<NominalTypeDecl>(d->getDeclContext());
    auto scope =
      nominal->getFormalAccessScope(/*useDC=*/nullptr,
                                    /*treatUsableFromInlineAsPublic=*/true);
    if (!scope.isPublic())
      return IsNotSerialized;
    if (nominal->isFormallyResilient())
      return IsNotSerialized;
    return IsSerialized;
  }

  // Note: if 'd' is a function, then 'dc' is the function itself, not
  // its parent context.
  dc = d->getInnermostDeclContext();

  // Local functions are serializable if their parent function is
  // serializable.
  if (d->getDeclContext()->isLocalContext()) {
    if (dc->getResilienceExpansion() == ResilienceExpansion::Minimal)
      return IsSerializable;

    return IsNotSerialized;
  }

  // Anything else that is not public is not serializable.
  if (d->getEffectiveAccess() < AccessLevel::Public)
    return IsNotSerialized;

  // 'read' and 'modify' accessors synthesized on-demand are serialized if
  // visible outside the module.
  if (auto fn = dyn_cast<FuncDecl>(d))
    if (!isClangImported() &&
        fn->hasForcedStaticDispatch())
      return IsSerialized;

  // Enum element constructors are serializable if the enum is
  // @usableFromInline or public.
  if (isEnumElement())
    return IsSerializable;

  // Currying thunks are serialized if referenced from an inlinable
  // context -- Sema's semantic checks ensure the serialization of
  // such a thunk is valid, since it must in turn reference a public
  // symbol, or dispatch via class_method or witness_method.
  if (isCurried)
    return IsSerializable;

  if (isForeignToNativeThunk())
    return IsSerializable;

  // The allocating entry point for designated initializers are serialized
  // if the class is @usableFromInline or public.
  if (kind == SILDeclRef::Kind::Allocator) {
    auto *ctor = cast<ConstructorDecl>(d);
    if (ctor->isDesignatedInit() &&
        ctor->getDeclContext()->getSelfClassDecl()) {
      if (!ctor->hasClangNode())
        return IsSerialized;
    }
  }

  if (isForeign) {
    // @objc thunks for methods are not serializable since they're only
    // referenced from the method table.
    if (d->getDeclContext()->isTypeContext())
      return IsNotSerialized;

    // @objc thunks for top-level functions are serializable since they're
    // referenced from @convention(c) conversions inside inlinable
    // functions.
    return IsSerializable;
  }

  // Declarations imported from Clang modules are serialized if
  // referenced from an inlinable context.
  if (isClangImported())
    return IsSerializable;

  // Otherwise, ask the AST if we're inside an @inlinable context.
  if (dc->getResilienceExpansion() == ResilienceExpansion::Minimal)
    return IsSerialized;

  return IsNotSerialized;
}
Exemplo n.º 18
0
  bool DeclExtractor::ExtractDecl(FunctionDecl* FD) {
    llvm::SmallVector<NamedDecl*, 4> TouchedDecls;
    CompoundStmt* CS = dyn_cast<CompoundStmt>(FD->getBody());
    assert(CS && "Function body not a CompoundStmt?");
    DeclContext* DC = FD->getTranslationUnitDecl();
    Scope* TUScope = m_Sema->TUScope;
    assert(TUScope == m_Sema->getScopeForContext(DC) && "TU scope from DC?");
    llvm::SmallVector<Stmt*, 4> Stmts;

    for (CompoundStmt::body_iterator I = CS->body_begin(), EI = CS->body_end();
         I != EI; ++I) {
      DeclStmt* DS = dyn_cast<DeclStmt>(*I);
      if (!DS) {
        Stmts.push_back(*I);
        continue;
      }
      
      for (DeclStmt::decl_iterator J = DS->decl_begin();
           J != DS->decl_end(); ++J) {
        NamedDecl* ND = dyn_cast<NamedDecl>(*J);
        if (isa<UsingDirectiveDecl>(*J))
          continue; // FIXME: Here we should be more elegant.
        if (ND) {
          if (Stmts.size()) {
            // We need to emit a new custom wrapper wrapping the stmts
            EnforceInitOrder(Stmts);
            assert(!Stmts.size() && "Stmt list must be flushed.");
          }

          // We know the transaction is closed, but it is safe.
          getTransaction()->forceAppend(ND);

          DeclContext* OldDC = ND->getDeclContext();

          // Make sure the decl is not found at its old possition
          ND->getLexicalDeclContext()->removeDecl(ND);
          if (Scope* S = m_Sema->getScopeForContext(OldDC)) {
            S->RemoveDecl(ND);
            if (utils::Analyze::isOnScopeChains(ND, *m_Sema))
              m_Sema->IdResolver.RemoveDecl(ND);
          }

          // For variable definitions causing var/function ambiguity such as:
          // MyClass my();, C++ standard says it shall be resolved as a function
          //
          // In the particular context this definition is inside a function
          // already, but clang thinks it as a lambda, so we need to ignore the
          // check decl context vs lexical decl context.
          if (ND->getDeclContext() == ND->getLexicalDeclContext()
              || isa<FunctionDecl>(ND))
            ND->setLexicalDeclContext(DC);
          else 
            assert(0 && "Not implemented: Decl with different lexical context");
          ND->setDeclContext(DC);

          if (VarDecl* VD = dyn_cast<VarDecl>(ND)) {
            VD->setStorageClass(SC_None);
          }

          clearLinkage(ND);

          TouchedDecls.push_back(ND);
        }
      }
    }
    bool hasNoErrors = !CheckForClashingNames(TouchedDecls, DC, TUScope);
    if (hasNoErrors) {
      for (size_t i = 0; i < TouchedDecls.size(); ++i) {
        // We should skip the checks for annonymous decls and we should not
        // register them in the lookup.
        if (!TouchedDecls[i]->getDeclName())
          continue;

        m_Sema->PushOnScopeChains(TouchedDecls[i],
                                  m_Sema->getScopeForContext(DC),
                    /*AddCurContext*/!isa<UsingDirectiveDecl>(TouchedDecls[i]));

        // The transparent DeclContexts (eg. scopeless enum) doesn't have 
        // scopes. While extracting their contents we need to update the
        // lookup tables and telling them to pick up the new possitions
        // in the AST.
        if (DeclContext* InnerDC = dyn_cast<DeclContext>(TouchedDecls[i])) {
          if (InnerDC->isTransparentContext()) {
            // We can't PushDeclContext, because we don't have scope.
            Sema::ContextRAII pushedDC(*m_Sema, InnerDC);

            for(DeclContext::decl_iterator DI = InnerDC->decls_begin(), 
                  DE = InnerDC->decls_end(); DI != DE ; ++DI) {
              if (NamedDecl* ND = dyn_cast<NamedDecl>(*DI))
                InnerDC->makeDeclVisibleInContext(ND);
            }
          }
        }
      }
    }

    CS->setStmts(*m_Context, Stmts.data(), Stmts.size());

    // The order matters, because when we extract decls from the wrapper we
    // append them to the transaction. If the transaction gets unloaded it will
    // introduce a fake dependency, so put the move last.
    Transaction* T = getTransaction();
    for (Transaction::iterator I = T->decls_begin(), E = T->decls_end();
         I != E; ++I)
      if (!I->m_DGR.isNull() && I->m_DGR.isSingleDecl()
          && I->m_DGR.getSingleDecl() == T->getWrapperFD()) {
        T->erase(I);
        break;
      }
    T->forceAppend(FD);

    // Put the wrapper after its declarations. (Nice when AST dumping)
    DC->removeDecl(FD);
    DC->addDecl(FD);

    return hasNoErrors;
  }
Exemplo n.º 19
0
ProtocolConformance *ConformanceLookupTable::getConformance(
                       NominalTypeDecl *nominal,
                       LazyResolver *resolver,
                       ConformanceEntry *entry) {
  // If we already have a conformance, we're done.
  if (auto conformance = entry->getConformance())
    return conformance;

  ProtocolDecl *protocol = entry->getProtocol();

  // Determine where the explicit conformance actually lives.
  // FIXME: This is a hack to ensure that inherited conformances are
  // always "single step", which is bad for resilience but is assumed
  // elsewhere in the compiler.
  DeclContext *conformingDC = getConformingContext(nominal, resolver, entry);
  if (!conformingDC)
    return nullptr;

  auto *conformingNominal =
    cast<NominalTypeDecl>(conformingDC->
                          getAsGenericTypeOrGenericTypeExtensionContext());

  // Form the conformance.
  Type type = entry->getDeclContext()->getDeclaredTypeInContext();
  ProtocolConformance *conformance;
    ASTContext &ctx = nominal->getASTContext();
  if (entry->getKind() == ConformanceEntryKind::Inherited) {
    // For an inherited conformance, the conforming nominal type will
    // be different from the nominal type.
    assert(conformingNominal != nominal && "Broken inherited conformance");

    // Find the superclass type that matches where the conformance was
    // declared.
    Type superclassTy = type->getSuperclass(resolver);
    while (superclassTy->getAnyNominal() != conformingNominal)
      superclassTy = superclassTy->getSuperclass(resolver);

    // Look up the inherited conformance.
    Module *module = entry->getDeclContext()->getParentModule();
    auto inheritedConformance = module->lookupConformance(superclassTy,
                                                          protocol,
                                                          resolver)
                                  .getPointer();

    // Form the inherited conformance.
    conformance = ctx.getInheritedConformance(
                    type,
                    inheritedConformance->getConcrete());
  } else {
    // Create or find the normal conformance.
    Type conformingType = conformingDC->getDeclaredTypeInContext();
    SourceLoc conformanceLoc
      = conformingNominal == conformingDC
          ? conformingNominal->getLoc()
          : cast<ExtensionDecl>(conformingDC)->getLoc();

    conformance = ctx.getConformance(conformingType, protocol, conformanceLoc,
                                     conformingDC,
                                     ProtocolConformanceState::Incomplete);
  }

  // Record the conformance.
  entry->Conformance = conformance;
  return conformance;
}
Exemplo n.º 20
0
  void DeclExtractor::EnforceInitOrder(llvm::SmallVectorImpl<Stmt*>& Stmts){
    Scope* TUScope = m_Sema->TUScope;
    DeclContext* TUDC = static_cast<DeclContext*>(TUScope->getEntity());
    // We can't PushDeclContext, because we don't have scope.
    Sema::ContextRAII pushedDC(*m_Sema, TUDC);

    std::string FunctionName = "__fd";
    createUniqueName(FunctionName);
    IdentifierInfo& IIFD = m_Context->Idents.get(FunctionName);
    SourceLocation Loc;
    NamedDecl* ND = m_Sema->ImplicitlyDefineFunction(Loc, IIFD, TUScope);
    if (FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(ND)) {
      FD->setImplicit(false); // Better for debugging

      // Add a return statement if it doesn't exist
      if (!isa<ReturnStmt>(Stmts.back())) {
        Sema::ContextRAII pushedDC(*m_Sema, FD);
        // Generate the return statement:
        // First a literal 0, then the return taking that literal.
        // One bit is enough:
        llvm::APInt ZeroInt(m_Context->getIntWidth(m_Context->IntTy), 0,
                            /*isSigned=*/true);
        IntegerLiteral* ZeroLit
          = IntegerLiteral::Create(*m_Context, ZeroInt, m_Context->IntTy,
                                   SourceLocation());
        Stmts.push_back(m_Sema->ActOnReturnStmt(ZeroLit->getExprLoc(), 
                                                ZeroLit).take());
      }

      // Wrap Stmts into a function body.
      llvm::ArrayRef<Stmt*> StmtsRef(Stmts.data(), Stmts.size());
      CompoundStmt* CS = new (*m_Context)CompoundStmt(*m_Context, StmtsRef,
                                                      Loc, Loc);
      FD->setBody(CS);
      // We know the transaction is closed, but it is safe.
      getTransaction()->forceAppend(FD);

      // Create the VarDecl with the init      
      std::string VarName = "__vd";
      createUniqueName(VarName);
      IdentifierInfo& IIVD = m_Context->Idents.get(VarName);
      VarDecl* VD = VarDecl::Create(*m_Context, TUDC, Loc, Loc, &IIVD,
                                    FD->getReturnType(), (TypeSourceInfo*)0,
                                    SC_None);
      LookupResult R(*m_Sema, FD->getDeclName(), Loc, Sema::LookupMemberName);
      R.addDecl(FD);
      CXXScopeSpec CSS;
      Expr* UnresolvedLookup
        = m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).take();
      Expr* TheCall = m_Sema->ActOnCallExpr(TUScope, UnresolvedLookup, Loc, 
                                            MultiExprArg(), Loc).take();
      assert(VD && TheCall && "Missing VD or its init!");
      VD->setInit(TheCall);

      // We know the transaction is closed, but it is safe.
      getTransaction()->forceAppend(VD); // Add it to the transaction for codegenning
      TUDC->addHiddenDecl(VD);
      Stmts.clear();
      return;
    }
    llvm_unreachable("Must be able to enforce init order.");
  }
Exemplo n.º 21
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;
  }
/// \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;
}
Exemplo n.º 23
0
SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const {
  if (getAbstractClosureExpr()) {
    return isSerialized() ? SILLinkage::Shared : SILLinkage::Private;
  }

  // Add External to the linkage (e.g. Public -> PublicExternal) if this is a
  // declaration not a definition.
  auto maybeAddExternal = [&](SILLinkage linkage) {
    return forDefinition ? linkage : addExternalToLinkage(linkage);
  };

  // Native function-local declarations have shared linkage.
  // FIXME: @objc declarations should be too, but we currently have no way
  // of marking them "used" other than making them external. 
  ValueDecl *d = getDecl();
  DeclContext *moduleContext = d->getDeclContext();
  while (!moduleContext->isModuleScopeContext()) {
    if (!isForeign && moduleContext->isLocalContext()) {
      return isSerialized() ? SILLinkage::Shared : SILLinkage::Private;
    }
    moduleContext = moduleContext->getParent();
  }

  // Enum constructors and curry thunks either have private or shared
  // linkage, dependings are essentially the same as thunks, they are
  // emitted by need and have shared linkage.
  if (isEnumElement() || isCurried) {
    switch (d->getEffectiveAccess()) {
    case AccessLevel::Private:
    case AccessLevel::FilePrivate:
      return maybeAddExternal(SILLinkage::Private);

    case AccessLevel::Internal:
    case AccessLevel::Public:
    case AccessLevel::Open:
      return SILLinkage::Shared;
    }
  }

  // Calling convention thunks have shared linkage.
  if (isForeignToNativeThunk())
    return SILLinkage::Shared;

  // If a function declares a @_cdecl name, its native-to-foreign thunk
  // is exported with the visibility of the function.
  if (isNativeToForeignThunk() && !d->getAttrs().hasAttribute<CDeclAttr>())
    return SILLinkage::Shared;

  // Declarations imported from Clang modules have shared linkage.
  if (isClangImported())
    return SILLinkage::Shared;

  // Default argument generators of Public functions have PublicNonABI linkage
  // if the function was type-checked in Swift 4 mode.
  if (kind == SILDeclRef::Kind::DefaultArgGenerator) {
    if (isSerialized())
      return maybeAddExternal(SILLinkage::PublicNonABI);
  }

  enum class Limit {
    /// No limit.
    None,
    /// The declaration is emitted on-demand; it should end up with internal
    /// or shared linkage.
    OnDemand,
    /// The declaration should never be made public.
    NeverPublic 
  };
  auto limit = Limit::None;

  // ivar initializers and destroyers are completely contained within the class
  // from which they come, and never get seen externally.
  if (isIVarInitializerOrDestroyer()) {
    limit = Limit::NeverPublic;
  }

  // Stored property initializers get the linkage of their containing type.
  if (isStoredPropertyInitializer()) {
    // Three cases:
    //
    // 1) Type is formally @_fixed_layout. Root initializers can be declared
    //    @inlinable. The property initializer must only reference
    //    public symbols, and is serialized, so we give it PublicNonABI linkage.
    //
    // 2) Type is not formally @_fixed_layout and the module is not resilient.
    //    Root initializers can be declared @inlinable. This is the annoying
    //    case. We give the initializer public linkage if the type is public.
    //
    // 3) Type is resilient. The property initializer is never public because
    //    root initializers cannot be @inlinable.
    //
    // FIXME: Get rid of case 2 somehow.
    if (isSerialized())
      return maybeAddExternal(SILLinkage::PublicNonABI);

    d = cast<NominalTypeDecl>(d->getDeclContext());

    // FIXME: This should always be true.
    if (d->getDeclContext()->getParentModule()->getResilienceStrategy() ==
        ResilienceStrategy::Resilient)
      limit = Limit::NeverPublic;
  }

  // The global addressor is never public for resilient globals.
  if (kind == Kind::GlobalAccessor) {
    if (cast<VarDecl>(d)->isResilient()) {
      limit = Limit::NeverPublic;
    }
  }

  // Forced-static-dispatch functions are created on-demand and have
  // at best shared linkage.
  if (auto fn = dyn_cast<FuncDecl>(d)) {
    if (fn->hasForcedStaticDispatch()) {
      limit = Limit::OnDemand;
    }
  }
  
  auto effectiveAccess = d->getEffectiveAccess();
  
  // Private setter implementations for an internal storage declaration should
  // be internal as well, so that a dynamically-writable
  // keypath can be formed from other files.
  if (auto accessor = dyn_cast<AccessorDecl>(d)) {
    if (accessor->isSetter()
       && accessor->getStorage()->getEffectiveAccess() == AccessLevel::Internal)
      effectiveAccess = AccessLevel::Internal;
  }

  switch (effectiveAccess) {
  case AccessLevel::Private:
  case AccessLevel::FilePrivate:
    return maybeAddExternal(SILLinkage::Private);

  case AccessLevel::Internal:
    if (limit == Limit::OnDemand)
      return SILLinkage::Shared;
    return maybeAddExternal(SILLinkage::Hidden);

  case AccessLevel::Public:
  case AccessLevel::Open:
    if (limit == Limit::OnDemand)
      return SILLinkage::Shared;
    if (limit == Limit::NeverPublic)
      return maybeAddExternal(SILLinkage::Hidden);
    return maybeAddExternal(SILLinkage::Public);
  }
  llvm_unreachable("unhandled access");
}
Exemplo n.º 24
0
SubclassScope SILDeclRef::getSubclassScope() const {
  if (!hasDecl())
    return SubclassScope::NotApplicable;

  auto *decl = getDecl();

  if (!isa<AbstractFunctionDecl>(decl))
    return SubclassScope::NotApplicable;

  // If this declaration is a function which goes into a vtable, then it's
  // symbol must be as visible as its class, because derived classes have to put
  // all less visible methods of the base class into their vtables.

  if (auto *CD = dyn_cast<ConstructorDecl>(decl)) {
    // Initializing entry points do not appear in the vtable.
    if (kind == SILDeclRef::Kind::Initializer)
      return SubclassScope::NotApplicable;
    // Non-required convenience inits do not apper in the vtable.
    if (!CD->isRequired() && !CD->isDesignatedInit())
      return SubclassScope::NotApplicable;
  } else if (isa<DestructorDecl>(decl)) {
    // Detructors do not appear in the vtable.
    return SubclassScope::NotApplicable;
  } else {
    assert(isa<FuncDecl>(decl));
  }

  DeclContext *context = decl->getDeclContext();

  // Methods from extensions don't go in the vtable.
  if (isa<ExtensionDecl>(context))
    return SubclassScope::NotApplicable;

  // Various forms of thunks don't either.
  if (isThunk() || isForeign)
    return SubclassScope::NotApplicable;

  // Default arg generators don't go in the vtable.
  if (isDefaultArgGenerator())
    return SubclassScope::NotApplicable;

  // Only non-final methods in non-final classes go in the vtable.
  auto *classType = context->getSelfClassDecl();
  if (!classType || classType->isFinal())
    return SubclassScope::NotApplicable;

  if (decl->isFinal())
    return SubclassScope::NotApplicable;

  assert(decl->getEffectiveAccess() <= classType->getEffectiveAccess() &&
         "class must be as visible as its members");

  // FIXME: This is too narrow. Any class with resilient metadata should
  // probably have this, at least for method overrides that don't add new
  // vtable entries.
  if (classType->isResilient()) {
    if (isa<ConstructorDecl>(decl))
      return SubclassScope::NotApplicable;
    return SubclassScope::Resilient;
  }

  switch (classType->getEffectiveAccess()) {
  case AccessLevel::Private:
  case AccessLevel::FilePrivate:
    return SubclassScope::NotApplicable;
  case AccessLevel::Internal:
  case AccessLevel::Public:
    return SubclassScope::Internal;
  case AccessLevel::Open:
    return SubclassScope::External;
  }

  llvm_unreachable("Unhandled access level in switch.");
}
Exemplo n.º 25
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;
}
Exemplo n.º 26
0
void SILGenFunction::emitMemberInitializers(DeclContext *dc,
                                            VarDecl *selfDecl,
                                            NominalTypeDecl *nominal) {
  for (auto member : nominal->getMembers()) {
    // Find instance pattern binding declarations that have initializers.
    if (auto pbd = dyn_cast<PatternBindingDecl>(member)) {
      if (pbd->isStatic()) continue;

      for (auto entry : pbd->getPatternList()) {
        auto init = entry.getInit();
        if (!init) continue;

        // Cleanup after this initialization.
        FullExpr scope(Cleanups, entry.getPattern());

        // Get the substitutions for the constructor context.
        SubstitutionList subs;
        auto *genericEnv = dc->getGenericEnvironmentOfContext();

        DeclContext *typeDC = dc;
        while (!typeDC->isTypeContext())
          typeDC = typeDC->getParent();
        auto typeGenericSig = typeDC->getGenericSignatureOfContext();

        if (genericEnv && typeGenericSig) {
          // Generate a set of substitutions for the initialization function,
          // whose generic signature is that of the type context, and whose
          // replacement types are the archetypes of the initializer itself.
          SmallVector<Substitution, 4> subsVec;
          typeGenericSig->getSubstitutions(
                       [&](SubstitutableType *type) {
                         if (auto gp = type->getAs<GenericTypeParamType>()) {
                           return genericEnv->mapTypeIntoContext(gp);
                         }

                         return Type(type);
                       },
                       [](CanType dependentType,
                           Type conformingReplacementType,
                           ProtocolType *conformedProtocol) {
                         return ProtocolConformanceRef(
                                  conformedProtocol->getDecl());
                       },
                       subsVec);
          subs = SGM.getASTContext().AllocateCopy(subsVec);
        }

        // Get the type of the initialization result, in terms
        // of the constructor context's archetypes.
        CanType resultType = getInitializationTypeInContext(
            pbd->getDeclContext(), dc, entry.getPattern())->getCanonicalType();
        AbstractionPattern origResultType(resultType);

        // FIXME: Can emitMemberInit() share code with
        // InitializationForPattern in SILGenDecl.cpp?
        RValue result = emitApplyOfStoredPropertyInitializer(
                                  init, entry, subs,
                                  resultType, origResultType,
                                  SGFContext());

        emitMemberInit(*this, selfDecl, entry.getPattern(), std::move(result));
      }
    }
    
    // Introduce behavior initialization markers for properties that need them.
    if (auto var = dyn_cast<VarDecl>(member)) {
      if (var->isStatic()) continue;
      if (!var->hasBehaviorNeedingInitialization()) continue;
      
      // Get the initializer method for behavior.
      auto init = var->getBehavior()->InitStorageDecl;
      SILValue initFn = getBehaviorInitStorageFn(*this, var);
      
      // Get the behavior's storage we need to initialize.
      auto storage = var->getBehavior()->StorageDecl;
      LValue storageRef = emitLValueForMemberInit(*this, var, selfDecl,storage);
      // Shed any reabstraction over the member.
      while (storageRef.isLastComponentTranslation())
        storageRef.dropLastTranslationComponent();
      
      auto storageAddr = emitAddressOfLValue(var, std::move(storageRef),
                                             AccessKind::ReadWrite);
      
      // Get the setter.
      auto setterFn = getBehaviorSetterFn(*this, var);
      auto self = emitSelfForMemberInit(*this, var, selfDecl);
      
      auto mark = B.createMarkUninitializedBehavior(var,
               initFn, init.getSubstitutions(), storageAddr.getValue(),
               setterFn, getForwardingSubstitutions(), self.getValue(),
               getLoweredType(var->getType()).getAddressType());
      
      // The mark instruction stands in for the behavior property.
      VarLocs[var].value = mark;
    }
  }
}
/// Do a syntactic pattern match to determine whether the call is a call
/// to swap(&base[index1], &base[index2]), which can
/// be replaced with a call to MutableCollection.swapAt(_:_:) on base.
///
/// Returns true if the call can be replaced. Returns the call expression,
/// the base expression, and the two indices as out expressions.
///
/// This method takes an array of all the ApplyInsts for calls to swap()
/// in the function to avoid needing to construct a parent map over the AST
/// to find the CallExpr for the inout accesses.
static bool
canReplaceWithCallToCollectionSwapAt(const BeginAccessInst *Access1,
                                     const BeginAccessInst *Access2,
                                     ArrayRef<ApplyInst *> CallsToSwap,
                                     ASTContext &Ctx,
                                     CallExpr *&FoundCall,
                                     Expr *&Base,
                                     Expr *&Index1,
                                     Expr *&Index2) {
  if (CallsToSwap.empty())
    return false;

  // Inout arguments must be modifications.
  if (Access1->getAccessKind() != SILAccessKind::Modify ||
      Access2->getAccessKind() != SILAccessKind::Modify) {
    return false;
  }

  SILLocation Loc1 = Access1->getLoc();
  SILLocation Loc2 = Access2->getLoc();
  if (Loc1.isNull() || Loc2.isNull())
    return false;

  auto *InOut1 = Loc1.getAsASTNode<InOutExpr>();
  auto *InOut2 = Loc2.getAsASTNode<InOutExpr>();
  if (!InOut1 || !InOut2)
    return false;

  FoundCall = nullptr;
  // Look through all the calls to swap() recorded in the function to find
  // which one we're diagnosing.
  for (ApplyInst *AI : CallsToSwap) {
    SILLocation CallLoc = AI->getLoc();
    if (CallLoc.isNull())
      continue;

    auto *CE = CallLoc.getAsASTNode<CallExpr>();
    if (!CE)
      continue;

    assert(isCallToStandardLibrarySwap(CE, Ctx));
    // swap() takes two arguments.
    auto *ArgTuple = cast<TupleExpr>(CE->getArg());
    const Expr *Arg1 = ArgTuple->getElement(0);
    const Expr *Arg2 = ArgTuple->getElement(1);
    if ((Arg1 == InOut1 && Arg2 == InOut2)) {
        FoundCall = CE;
      break;
    }
  }
  if (!FoundCall)
    return false;

  // We found a call to swap(&e1, &e2). Now check to see whether it
  // matches the form swap(&someCollection[index1], &someCollection[index2]).
  auto *SE1 = dyn_cast<SubscriptExpr>(InOut1->getSubExpr());
  if (!SE1)
    return false;
  auto *SE2 = dyn_cast<SubscriptExpr>(InOut2->getSubExpr());
  if (!SE2)
    return false;

  // Do the two subscripts refer to the same subscript declaration?
  auto *Decl1 = cast<SubscriptDecl>(SE1->getDecl().getDecl());
  auto *Decl2 = cast<SubscriptDecl>(SE2->getDecl().getDecl());
  if (Decl1 != Decl2)
    return false;

  ProtocolDecl *MutableCollectionDecl = Ctx.getMutableCollectionDecl();

  // Is the subcript either (1) on MutableCollection itself or (2) a
  // a witness for a subscript on MutableCollection?
  bool IsSubscriptOnMutableCollection = false;
  ProtocolDecl *ProtocolForDecl =
      Decl1->getDeclContext()->getSelfProtocolDecl();
  if (ProtocolForDecl) {
    IsSubscriptOnMutableCollection = (ProtocolForDecl == MutableCollectionDecl);
  } else {
    for (ValueDecl *Req : Decl1->getSatisfiedProtocolRequirements()) {
      DeclContext *ReqDC = Req->getDeclContext();
      ProtocolDecl *ReqProto = ReqDC->getSelfProtocolDecl();
      assert(ReqProto && "Protocol requirement not in a protocol?");

      if (ReqProto == MutableCollectionDecl) {
        IsSubscriptOnMutableCollection = true;
        break;
      }
    }
  }

  if (!IsSubscriptOnMutableCollection)
    return false;

  // We're swapping two subscripts on mutable collections -- but are they
  // the same collection? Approximate this by checking for textual
  // equality on the base expressions. This is just an approximation,
  // but is fine for a best-effort Fix-It.
  SourceManager &SM = Ctx.SourceMgr;
  StringRef Base1Text = extractExprText(SE1->getBase(), SM);
  StringRef Base2Text = extractExprText(SE2->getBase(), SM);

  if (Base1Text != Base2Text)
    return false;

  auto *Index1Paren = dyn_cast<ParenExpr>(SE1->getIndex());
  if (!Index1Paren)
    return false;

  auto *Index2Paren = dyn_cast<ParenExpr>(SE2->getIndex());
  if (!Index2Paren)
    return false;

  Base = SE1->getBase();
  Index1 = Index1Paren->getSubExpr();
  Index2 = Index2Paren->getSubExpr();
  return true;
}
Exemplo n.º 28
0
/// \brief True if the function should have its body serialized.
IsSerialized_t SILDeclRef::isSerialized() const {
  DeclContext *dc;
  if (auto closure = getAbstractClosureExpr())
    dc = closure->getLocalContext();
  else {
    auto *d = getDecl();

    // Default argument generators are serialized if the function was
    // type-checked in Swift 4 mode.
    if (kind == SILDeclRef::Kind::DefaultArgGenerator) {
      auto *afd = cast<AbstractFunctionDecl>(d);
      switch (afd->getDefaultArgumentResilienceExpansion()) {
      case ResilienceExpansion::Minimal:
        return IsSerialized;
      case ResilienceExpansion::Maximal:
        return IsNotSerialized;
      }
    }

    // 'read' and 'modify' accessors synthesized on-demand are serialized if
    // visible outside the module.
    if (auto fn = dyn_cast<FuncDecl>(d))
      if (!isClangImported() &&
          fn->hasForcedStaticDispatch() &&
          fn->getEffectiveAccess() >= AccessLevel::Public)
        return IsSerialized;

    dc = getDecl()->getInnermostDeclContext();

    // Enum element constructors are serialized if the enum is
    // @usableFromInline or public.
    if (isEnumElement())
      if (d->getEffectiveAccess() >= AccessLevel::Public)
        return IsSerialized;

    // Currying thunks are serialized if referenced from an inlinable
    // context -- Sema's semantic checks ensure the serialization of
    // such a thunk is valid, since it must in turn reference a public
    // symbol, or dispatch via class_method or witness_method.
    if (isCurried)
      if (d->getEffectiveAccess() >= AccessLevel::Public)
        return IsSerializable;

    if (isForeignToNativeThunk())
      return IsSerializable;

    // The allocating entry point for designated initializers are serialized
    // if the class is @usableFromInline or public.
    if (kind == SILDeclRef::Kind::Allocator) {
      auto *ctor = cast<ConstructorDecl>(d);
      if (ctor->isDesignatedInit() &&
          ctor->getDeclContext()->getSelfClassDecl()) {
        if (ctor->getEffectiveAccess() >= AccessLevel::Public &&
            !ctor->hasClangNode())
          return IsSerialized;
      }
    }

    // Stored property initializers are inlinable if the type is explicitly
    // marked as @_fixed_layout.
    if (isStoredPropertyInitializer()) {
      auto *nominal = cast<NominalTypeDecl>(d->getDeclContext());
      auto scope =
        nominal->getFormalAccessScope(/*useDC=*/nullptr,
                                      /*treatUsableFromInlineAsPublic=*/true);
      if (!scope.isPublic())
        return IsNotSerialized;
      if (nominal->isFormallyResilient())
        return IsNotSerialized;
      return IsSerialized;
    }
  }

  // Declarations imported from Clang modules are serialized if
  // referenced from an inlinable context.
  if (isClangImported())
    return IsSerializable;

  // Otherwise, ask the AST if we're inside an @inlinable context.
  if (dc->getResilienceExpansion() == ResilienceExpansion::Minimal)
    return IsSerialized;

  return IsNotSerialized;
}
Exemplo n.º 29
0
  bool ValuePrinterSynthesizer::tryAttachVP(FunctionDecl* FD) {
    // We have to be able to mark the expression for printout. There are
    // three scenarios:
    // 0: Expression printing disabled - don't do anything just exit.
    // 1: Expression printing enabled - print no matter what.
    // 2: Expression printing auto - analyze - rely on the omitted ';' to
    //    not produce the suppress marker.
    int indexOfLastExpr = -1;
    Expr* To = utils::Analyze::GetOrCreateLastExpr(FD, &indexOfLastExpr,
                                                   /*omitDS*/false,
                                                   m_Sema);
    if (To) {
      // Update the CompoundStmt body, avoiding alloc/dealloc of all the el.
      CompoundStmt* CS = cast<CompoundStmt>(FD->getBody());
      assert(CS && "Missing body?");

      switch (getCompilationOpts().ValuePrinting) {
      case CompilationOptions::VPDisabled:
        assert(0 && "Don't wait that long. Exit early!");
        break;
      case CompilationOptions::VPEnabled:
        break;
      case CompilationOptions::VPAuto: {
        // FIXME: Propagate the flag to the nested transactions also, they
        // must have the same CO as their parents.
        getCompilationOpts().ValuePrinting = CompilationOptions::VPEnabled;
        if ((int)CS->size() > indexOfLastExpr+1
            && (*(CS->body_begin() + indexOfLastExpr + 1))
            && isa<NullStmt>(*(CS->body_begin() + indexOfLastExpr + 1))) {
          // If next is NullStmt disable VP is disabled - exit. Signal this in
          // the CO of the transaction.
          getCompilationOpts().ValuePrinting = CompilationOptions::VPDisabled;
        }
        if (getCompilationOpts().ValuePrinting
            == CompilationOptions::VPDisabled)
          return true;
      }
        break;
      }

      // We can't PushDeclContext, because we don't have scope.
      Sema::ContextRAII pushedDC(*m_Sema, FD);

      if (To) {
        // Strip the parenthesis if any
        if (ParenExpr* PE = dyn_cast<ParenExpr>(To))
          To = PE->getSubExpr();

        Expr* Result = 0;
        // if (!m_Sema->getLangOpts().CPlusPlus)
        //   Result = SynthesizeVP(To);

        if (Result)
          *(CS->body_begin()+indexOfLastExpr) = Result;
      }
      // Clear the artificial NullStmt-s
      if (!ClearNullStmts(CS)) {
        // FIXME: Why it is here? Shouldn't it be in DeclExtractor?
        // if no body remove the wrapper
        DeclContext* DC = FD->getDeclContext();
        Scope* S = m_Sema->getScopeForContext(DC);
        if (S)
          S->RemoveDecl(FD);
        DC->removeDecl(FD);
      }
    }
    else // if nothing to attach to set the CO's ValuePrinting to disabled.
      getCompilationOpts().ValuePrinting = CompilationOptions::VPDisabled;
    return true;
  }
Exemplo n.º 30
0
/// Check the generic parameters in the given generic parameter list (and its
/// parent generic parameter lists) according to the given resolver.
bool TypeChecker::checkGenericParamList(ArchetypeBuilder *builder,
                                        GenericParamList *genericParams,
                                        GenericSignature *parentSig,
                                        bool adoptArchetypes,
                                        GenericTypeResolver *resolver) {
  bool invalid = false;

  // If there is a parent context, add the generic parameters and requirements
  // from that context.
  if (builder)
    builder->addGenericSignature(parentSig, adoptArchetypes);

  // If there aren't any generic parameters at this level, we're done.
  if (!genericParams)
    return false;

  assert(genericParams->size() > 0 && "Parsed an empty generic parameter list?");

  // Determine where and how to perform name lookup for the generic
  // parameter lists and where clause.
  TypeResolutionOptions options;
  DeclContext *lookupDC = genericParams->begin()[0]->getDeclContext();
  if (!lookupDC->isModuleScopeContext()) {
    assert(isa<GenericTypeDecl>(lookupDC) || isa<ExtensionDecl>(lookupDC) ||
           isa<AbstractFunctionDecl>(lookupDC) &&
           "not a proper generic parameter context?");
    options = TR_GenericSignature;
  }    

  // First, set the depth of each generic parameter, and add them to the
  // archetype builder. Do this before checking the inheritance clause,
  // since it may itself be dependent on one of these parameters.
  unsigned depth = genericParams->getDepth();
  for (auto param : *genericParams) {
    param->setDepth(depth);

    if (builder) {
      if (builder->addGenericParameter(param))
        invalid = true;
    }
  }

  // Now, check the inheritance clauses of each parameter.
  for (auto param : *genericParams) {
    checkInheritanceClause(param, resolver);

    if (builder) {
      builder->addGenericParameterRequirements(param);

      // Infer requirements from the inherited types.
      for (const auto &inherited : param->getInherited()) {
        if (builder->inferRequirements(inherited, genericParams))
          invalid = true;
      }
    }
  }

  // Visit each of the requirements, adding them to the builder.
  // Add the requirements clause to the builder, validating the types in
  // the requirements clause along the way.
  for (auto &req : genericParams->getRequirements()) {
    if (req.isInvalid())
      continue;

    switch (req.getKind()) {
    case RequirementReprKind::TypeConstraint: {
      // Validate the types.
      if (validateType(req.getSubjectLoc(), lookupDC, options, resolver)) {
        invalid = true;
        req.setInvalid();
        continue;
      }

      if (validateType(req.getConstraintLoc(), lookupDC, options,
                       resolver)) {
        invalid = true;
        req.setInvalid();
        continue;
      }

      // FIXME: Feels too early to perform this check.
      if (!req.getConstraint()->isExistentialType() &&
          !req.getConstraint()->getClassOrBoundGenericClass()) {
        diagnose(genericParams->getWhereLoc(),
                 diag::requires_conformance_nonprotocol,
                 req.getSubjectLoc(), req.getConstraintLoc());
        req.getConstraintLoc().setInvalidType(Context);
        invalid = true;
        req.setInvalid();
        continue;
      }

      break;
    }

    case RequirementReprKind::SameType:
      if (validateType(req.getFirstTypeLoc(), lookupDC, options,
                       resolver)) {
        invalid = true;
        req.setInvalid();
        continue;
      }

      if (validateType(req.getSecondTypeLoc(), lookupDC, options,
                       resolver)) {
        invalid = true;
        req.setInvalid();
        continue;
      }
      
      break;
    }
    
    if (builder && builder->addRequirement(req)) {
      invalid = true;
      req.setInvalid();
    }
  }

  return invalid;
}