oop* InterpretedIC::inline_cache_miss() { NoGCVerifier noGC; // get ic info frame f = DeltaProcess::active()->last_frame(); InterpretedIC* ic = f.current_interpretedIC(); Bytecodes::Code send_code = ic->send_code(); oop receiver = ic->argument_spec() == Bytecodes::args_only // Are we at a self or super send? ? f.receiver() // yes: take receiver of frame : f.expr(ic->nof_arguments()); // no: take receiver pushed before the arguments // do the lookup klassOop klass = receiver->klass(); LookupResult result = Bytecodes::is_super_send(send_code) ? interpreter_super_lookup(ic->selector()) : interpreter_normal_lookup(klass, ic->selector()); // tracing if (TraceInlineCacheMiss) { std->print("IC miss, "); trace_inline_cache_miss(ic, klass, result); } // handle the lookup result if (!result.is_empty()) { update_inline_cache(ic, &f, ic->send_code(), klass, result); return NULL; } else { return cacheMissResult(does_not_understand(receiver, ic, &f), ic->nof_arguments() + (ic->argument_spec() == Bytecodes::args_only ? 0 : 1))->objs(1); } }
RasterImage::WillDrawOpaqueNow() { if (!IsOpaque()) { return false; } if (mAnimationState) { // We never discard frames of animated images. return true; } // If we are not locked our decoded data could get discard at any time (ie // between the call to this function and when we are asked to draw), so we // have to return false if we are unlocked. if (IsUnlocked()) { return false; } LookupResult result = SurfaceCache::LookupBestMatch(ImageKey(this), RasterSurfaceKey(mSize, DefaultSurfaceFlags(), PlaybackType::eStatic)); MatchType matchType = result.Type(); if (matchType == MatchType::NOT_FOUND || matchType == MatchType::PENDING || !result.Surface()->IsFinished()) { return false; } return true; }
QList<Coordinate> CollisionMapEntry::compile() const { QList<Coordinate> points; foreach(const Coordinate &coordinate, m_coordinates) { int offset = 1; int size = offset * 2; int x = coordinate.first; int y = coordinate.second; int hits = 0; for(int xr = x - offset; xr < x + size; xr++) { for(int yr = y - offset; yr < y + size; yr++) { Coordinate query(xr, yr); LookupResult result = m_coordinates.contains(query); if(result.isValid()) { hits++; } } } if(hits < 8) { points << coordinate; } }
bool DynamicIDHandler::IsDynamicLookup (LookupResult& R, Scope* S) { if (R.getLookupKind() != Sema::LookupOrdinaryName) return false; if (R.isForRedeclaration()) return false; // FIXME: Figure out better way to handle: // C++ [basic.lookup.classref]p1: // In a class member access expression (5.2.5), if the . or -> token is // immediately followed by an identifier followed by a <, the // identifier must be looked up to determine whether the < is the // beginning of a template argument list (14.2) or a less-than operator. // The identifier is first looked up in the class of the object // expression. If the identifier is not found, it is then looked up in // the context of the entire postfix-expression and shall name a class // or function template. // // We want to ignore object(.|->)member<template> if (m_Sema->PP.LookAhead(0).getKind() == tok::less) // TODO: check for . or -> in the cached token stream return false; for (Scope* DepScope = S; DepScope; DepScope = DepScope->getParent()) { if (DeclContext* Ctx = static_cast<DeclContext*>(DepScope->getEntity())) { return !Ctx->isDependentContext(); } } return true; }
already_AddRefed<gfxDrawable> VectorImage::LookupCachedSurface(const SVGDrawingParameters& aParams) { // If we're not allowed to use a cached surface, don't attempt a lookup. if (aParams.flags & FLAG_BYPASS_SURFACE_CACHE) { return nullptr; } // We don't do any caching if we have animation, so don't bother with a lookup // in this case either. if (mHaveAnimations) { return nullptr; } LookupResult result = SurfaceCache::Lookup(ImageKey(this), VectorSurfaceKey(aParams.size, aParams.svgContext)); if (!result) { return nullptr; // No matching surface, or the OS freed the volatile buffer. } RefPtr<SourceSurface> sourceSurface = result.Surface()->GetSourceSurface(); if (!sourceSurface) { // Something went wrong. (Probably a GPU driver crash or device reset.) // Attempt to recover. RecoverFromLossOfSurfaces(); return nullptr; } RefPtr<gfxDrawable> svgDrawable = new gfxSurfaceDrawable(sourceSurface, result.Surface()->GetSize()); return svgDrawable.forget(); }
bool DynamicIDHandler::LookupUnqualified(LookupResult& R, Scope* S) { if (!IsDynamicLookup(R, S)) return false; if (Callbacks && Callbacks->isEnabled()) { return Callbacks->LookupObject(R, S); } DeclarationName Name = R.getLookupName(); IdentifierInfo* II = Name.getAsIdentifierInfo(); SourceLocation Loc = R.getNameLoc(); VarDecl* Result = VarDecl::Create(m_Context, R.getSema().getFunctionLevelDeclContext(), Loc, Loc, II, m_Context.DependentTy, /*TypeSourceInfo*/0, SC_None, SC_None); if (Result) { R.addDecl(Result); // Say that we can handle the situation. Clang should try to recover return true; } // We cannot handle the situation. Give up return false; }
ExprResult Sema::BuildDefinitionNameExpr(LookupResult &R, bool ADL) { if(R.isSingleResult()) { return BuildDefinitionNameExpr(R.getLookupNameInfo(), R.getFoundDefn()); } return ExprError(); }
LookupResult FrameAnimator::GetCompositedFrame(AnimationState& aState) { // If we have a composited version of this frame, return that. if (mLastCompositedFrameIndex >= 0 && (uint32_t(mLastCompositedFrameIndex) == aState.mCurrentAnimationFrameIndex)) { return LookupResult(DrawableSurface(mCompositingFrame->DrawableRef()), MatchType::EXACT); } // Otherwise return the raw frame. DoBlend is required to ensure that we only // hit this case if the frame is not paletted and doesn't require compositing. LookupResult result = SurfaceCache::Lookup(ImageKey(mImage), RasterSurfaceKey(mSize, DefaultSurfaceFlags(), PlaybackType::eAnimated)); if (!result) { return result; } // Seek to the appropriate frame. If seeking fails, it means that we couldn't // get the frame we're looking for; treat this as if the lookup failed. if (NS_FAILED(result.Surface().Seek(aState.mCurrentAnimationFrameIndex))) { return LookupResult(MatchType::NOT_FOUND); } MOZ_ASSERT(!result.Surface()->GetIsPaletted(), "About to return a paletted frame"); return result; }
/// LookupBuiltin - Lookup for built-in functions static bool LookupBuiltin(Sema &S, LookupResult &R) { Sema::LookupNameKind NameKind = R.getLookupKind(); // If we didn't find a use of this identifier, and if the identifier // corresponds to a compiler builtin, create the defn object for the builtin // now, injecting it into system scope, and return it. if (NameKind == Sema::LookupOrdinaryName) { IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo(); if (II) { // If this is a builtin on this (or all) targets, create the defn. if (unsigned BuiltinID = II->getBuiltinID()) { if (NamedDefn *D = S.LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, S.BaseWorkspace, /*R.isForRedeclaration()*/false, R.getNameLoc())) { R.addDefn(D); return true; } //FIXME yabin // should i deal with this situation in gmat? // if (R.isForRedeclaration()) { // // If we're redeclaring this function anyway, forget that // // this was a builtin at all. // S.Context.BuiltinInfo.ForgetBuiltin(BuiltinID, // S.Context.Idents); // } return false; } } } return false; }
void InterpretedIC::inline_cache_miss() { NoGCVerifier noGC; // get ic info frame f = DeltaProcess::active()->last_frame(); InterpretedIC* ic = f.current_interpretedIC(); Bytecodes::Code send_code = ic->send_code(); oop receiver = ic->argument_spec() == Bytecodes::args_only // Are we at a self or super send? ? f.receiver() // yes: take receiver of frame : f.expr(ic->nof_arguments()); // no: take receiver pushed before the arguments // do the lookup klassOop klass = receiver->klass(); LookupResult result = Bytecodes::is_super_send(send_code) ? interpreter_super_lookup(ic->selector()) : interpreter_normal_lookup(klass, ic->selector()); // tracing if (TraceMessageSend) std->print_cr("inline cache miss"); if (TraceLookup) trace_inline_cache_miss(ic, klass, result); // handle the lookup result if (!result.is_empty()) update_inline_cache(ic, &f, send_code, klass, result); else { does_not_understand(receiver, ic, &f); // If the program continues we'll redo the inline_cache_miss if (!have_nlr_through_C) inline_cache_miss(); } }
LookupResult TypeChecker::lookupMember(DeclContext *dc, Type type, DeclName name, NameLookupOptions options) { assert(type->mayHaveMembers()); LookupResult result; NLOptions subOptions = NL_QualifiedDefault; if (options.contains(NameLookupFlags::KnownPrivate)) subOptions |= NL_KnownNonCascadingDependency; if (options.contains(NameLookupFlags::DynamicLookup)) subOptions |= NL_DynamicLookup; if (options.contains(NameLookupFlags::IgnoreAccessibility)) subOptions |= NL_IgnoreAccessibility; NominalTypeDecl *nominalLookupType = type->getAnyNominal(); if (options.contains(NameLookupFlags::ProtocolMembers)) subOptions |= NL_ProtocolMembers; // We handle our own overriding/shadowing filtering. subOptions &= ~NL_RemoveOverridden; subOptions &= ~NL_RemoveNonVisible; // Local function that performs lookup. auto doLookup = [&]() { result.clear(); LookupResultBuilder builder(*this, result, dc, options, /*memberLookup*/true); SmallVector<ValueDecl *, 4> lookupResults; dc->lookupQualified(type, name, subOptions, this, lookupResults); for (auto found : lookupResults) { builder.add(found, nominalLookupType, type); } }; doLookup(); if (result.empty()) { // If we didn't find anything, /and/ this is a nominal type, check to see // if any of the nominal's protocols are derivable and contain the // name we're looking for. (Note that we are not including extensions // here -- default derivation doesn't apply in extensions.) if (!nominalLookupType) return result; // Force the creation of any delayed members, to ensure proper member // lookup. this->forceExternalDeclMembers(nominalLookupType); // Perform the lookup again. // FIXME: This is only because forceExternalDeclMembers() might do something // interesting. doLookup(); } return result; }
RawAccessFrameRef FrameAnimator::GetRawFrame(uint32_t aFrameNum) const { LookupResult result = SurfaceCache::Lookup(ImageKey(mImage), RasterSurfaceKey(mSize, DefaultSurfaceFlags(), aFrameNum)); return result ? result.DrawableRef()->RawAccessRef() : RawAccessFrameRef(); }
bool SymbolResolverCallback::LookupObject(LookupResult& R, Scope* S) { if (!ShouldResolveAtRuntime(R, S)) return false; if (m_IsRuntime) { // We are currently parsing an EvaluateT() expression if (!m_Resolve) return false; // Only for demo resolve all unknown objects to cling::test::Tester if (!m_TesterDecl) { clang::Sema& SemaR = m_Interpreter->getSema(); clang::NamespaceDecl* NSD = utils::Lookup::Namespace(&SemaR, "cling"); NSD = utils::Lookup::Namespace(&SemaR, "test", NSD); m_TesterDecl = utils::Lookup::Named(&SemaR, "Tester", NSD); } assert (m_TesterDecl && "Tester not found!"); R.addDecl(m_TesterDecl); return true; // Tell clang to continue. } // We are currently NOT parsing an EvaluateT() expression. // Escape the expression into an EvaluateT() expression. ASTContext& C = R.getSema().getASTContext(); DeclContext* DC = 0; // For DeclContext-less scopes like if (dyn_expr) {} while (!DC) { DC = static_cast<DeclContext*>(S->getEntity()); S = S->getParent(); } DeclarationName Name = R.getLookupName(); IdentifierInfo* II = Name.getAsIdentifierInfo(); SourceLocation Loc = R.getNameLoc(); VarDecl* Res = VarDecl::Create(C, DC, Loc, Loc, II, C.DependentTy, /*TypeSourceInfo*/0, SC_None); // Annotate the decl to give a hint in cling. FIXME: Current implementation // is a gross hack, because TClingCallbacks shouldn't know about // EvaluateTSynthesizer at all! SourceRange invalidRange; Res->addAttr(new (C) AnnotateAttr(invalidRange, C, "__ResolveAtRuntime", 0)); R.addDecl(Res); DC->addDecl(Res); // Say that we can handle the situation. Clang should try to recover return true; }
bool Sema::OOPLookupName(LookupResult &R, Scope *S) { assert(getLangOptions().OOP && "Can perform only OOP lookup"); DefinitionName Name = R.getLookupName(); IdentifierResolver::iterator I = IdResolver.begin(Name), IEnd = IdResolver.end(); // First we lookup local scope. for (; S /*&& !isNamespaceOrTranslationUnitScope(S)*/; S = S->getParent()) { DefnContext *Ctx = static_cast<DefnContext *>(S->getEntity()); // Check whether the IdResolver has anything in this scope. bool Found = false; for (; I != IEnd && S->isDefnScope(*I); ++I) { if (R.isAcceptableDefn(*I)) { Found = true; R.addDefn(*I); } } if (Found) { R.resolveKind(); if (S->isClassScope()) if (UserClassDefn *Record = dyn_cast_or_null<UserClassDefn>(Ctx)) R.setNamingClass(Record); return true; } if (Ctx) { for (; Ctx; Ctx = Ctx->getParent()) { // We do not look directly into function or method contexts, // since all of the local variables and parameters of the // function/method are present within the Scope. if (Ctx->isFunctionOrMethod()) { continue; } // Perform qualified name lookup into this context. // FIXME: In some cases, we know that every name that could be found by // this qualified name lookup will also be on the identifier chain. For // example, inside a class without any base classes, we never need to // perform qualified lookup because all of the members are on top of the // identifier chain. if (LookupQualifiedName(R, Ctx, /*InUnqualifiedLookup=*/true)) return true; } } } // Stop if we ran out of scopes. // FIXME: This really, really shouldn't be happening. if (!S) return false; // If we are looking for members, no need to look into global/namespace scope. if (R.getLookupKind() == LookupMemberName) return false; return !R.empty(); }
void TypeChecker::performTypoCorrection(DeclContext *DC, DeclRefKind refKind, Type baseTypeOrNull, DeclName targetDeclName, SourceLoc nameLoc, NameLookupOptions lookupOptions, LookupResult &result, unsigned maxResults) { // Disable typo-correction if we won't show the diagnostic anyway. if (getLangOpts().DisableTypoCorrection || (Diags.hasFatalErrorOccurred() && !Diags.getShowDiagnosticsAfterFatalError())) return; // Fill in a collection of the most reasonable entries. TopCollection<unsigned, ValueDecl*> entries(maxResults); auto consumer = makeDeclConsumer([&](ValueDecl *decl, DeclVisibilityKind reason) { // Never match an operator with an identifier or vice-versa; this is // not a plausible typo. if (!isPlausibleTypo(refKind, targetDeclName, decl)) return; // Don't suggest a variable within its own initializer. if (auto var = dyn_cast<VarDecl>(decl)) { if (isLocInVarInit(*this, var, nameLoc)) return; } // Don't waste time computing edit distances that are more than // the worst in our collection. unsigned maxDistance = entries.getMinUninterestingScore(UnreasonableCallEditDistance); unsigned distance = getCallEditDistance(targetDeclName, decl->getFullName(), maxDistance); // Ignore values that are further than a reasonable distance. if (distance >= UnreasonableCallEditDistance) return; entries.insert(distance, std::move(decl)); }); TypoCorrectionResolver resolver(*this, nameLoc); if (baseTypeOrNull) { lookupVisibleMemberDecls(consumer, baseTypeOrNull, DC, &resolver, /*include instance members*/ true); } else { lookupVisibleDecls(consumer, DC, &resolver, /*top level*/ true, nameLoc); } // Impose a maximum distance from the best score. entries.filterMaxScoreRange(MaxCallEditDistanceFromBestCandidate); for (auto &entry : entries) result.add({ entry.Value, nullptr }); }
LookupResult lookup(klassOop klass, symbolOop selector) { if (!match(klass, selector)) { _result = interpreter_normal_lookup(klass, selector); if (!_result.is_empty()) { _key.initialize(klass, selector); } } return _result; }
void InterpretedIC::trace_inline_cache_miss(InterpretedIC* ic, klassOop klass, LookupResult result) { std->print("InterpretedIC lookup ("); klass->print_value(); std->print(", "); ic->selector()->print_value(); std->print(") --> "); result.print_short_on(std); std->cr(); }
//===----------------------------------------------------------------------===// // Sema //===----------------------------------------------------------------------===// bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { DefinitionName Name = R.getLookupName(); if (!Name) return false; // FIXME yabin // LookupNameKind NameKind = R.getLookupKind(); if (!getLangOptions().OOP) { // Unqualified name lookup in non-oop is purely lexical, so // search in the definitions attached to the name. unsigned IDNS = R.getIdentifierNamespace(); // Scan up the scope chain looking for a defn that matches this // identifier that is in the appropriate namespace. This search // should not take long, as shadowing of names is uncommon, and // deep shadowing is extremely uncommon. // bool LeftStartingScope = false; for (IdentifierResolver::iterator I = IdResolver.begin(Name), IEnd = IdResolver.end(); I != IEnd; ++I) { if ((*I)->isInIdentifierNamespace(IDNS)) { R.addDefn(*I); R.resolveKind(); return true; } } } else { // Perform OOP unqualified name lookup. if (OOPLookupName(R, S)) return true; } // If we didn't find a use of this identifier, and if the identifier // corresponds to a compiler builtin, create the defn object for the builtin // now, injecting it into top scope, and return it. if (AllowBuiltinCreation) return LookupBuiltin(*this, R); return false; }
LookupResult FrameAnimator::GetCompositedFrame(uint32_t aFrameNum) { MOZ_ASSERT(aFrameNum != 0, "First frame is never composited"); // If we have a composited version of this frame, return that. if (mLastCompositedFrameIndex == int32_t(aFrameNum)) { return LookupResult(mCompositingFrame->DrawableRef(), MatchType::EXACT); } // Otherwise return the raw frame. DoBlend is required to ensure that we only // hit this case if the frame is not paletted and doesn't require compositing. LookupResult result = SurfaceCache::Lookup(ImageKey(mImage), RasterSurfaceKey(mSize, DefaultSurfaceFlags(), aFrameNum)); MOZ_ASSERT(!result || !result.DrawableRef()->GetIsPaletted(), "About to return a paletted frame"); return result; }
RawAccessFrameRef FrameAnimator::GetRawFrame(uint32_t aFrameNum) const { LookupResult result = SurfaceCache::Lookup(ImageKey(mImage), RasterSurfaceKey(mSize, DefaultSurfaceFlags(), PlaybackType::eAnimated)); if (!result) { return RawAccessFrameRef(); } // Seek to the frame we want. If seeking fails, it means we couldn't get the // frame we're looking for, so we bail here to avoid returning the wrong frame // to the caller. if (NS_FAILED(result.Surface().Seek(aFrameNum))) { return RawAccessFrameRef(); // Not available yet. } return result.Surface()->RawAccessRef(); }
void FindAndCacheRuntimeLookupResult() { assert(!m_clingthrowIfInvalidPointerCache && "Called multiple times!?"); DeclarationName Name = &m_Context.Idents.get("cling_runtime_internal_throwIfInvalidPointer"); SourceLocation noLoc; m_clingthrowIfInvalidPointerCache = new LookupResult(m_Sema, Name, noLoc, Sema::LookupOrdinaryName, Sema::ForRedeclaration); m_Sema.LookupQualifiedName(*m_clingthrowIfInvalidPointerCache, m_Context.getTranslationUnitDecl()); assert(!m_clingthrowIfInvalidPointerCache->empty() && "Lookup of cling_runtime_internal_throwIfInvalidPointer failed!"); }
// With -fcuda-host-device-constexpr, an unattributed constexpr function is // treated as implicitly __host__ __device__, unless: // * it is a variadic function (device-side variadic functions are not // allowed), or // * a __device__ function with this signature was already declared, in which // case in which case we output an error, unless the __device__ decl is in a // system header, in which case we leave the constexpr function unattributed. // // In addition, all function decls are treated as __host__ __device__ when // ForceCUDAHostDeviceDepth > 0 (corresponding to code within a // #pragma clang force_cuda_host_device_begin/end // pair). void Sema::maybeAddCUDAHostDeviceAttrs(Scope *S, FunctionDecl *NewD, const LookupResult &Previous) { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); if (ForceCUDAHostDeviceDepth > 0) { if (!NewD->hasAttr<CUDAHostAttr>()) NewD->addAttr(CUDAHostAttr::CreateImplicit(Context)); if (!NewD->hasAttr<CUDADeviceAttr>()) NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context)); return; } if (!getLangOpts().CUDAHostDeviceConstexpr || !NewD->isConstexpr() || NewD->isVariadic() || NewD->hasAttr<CUDAHostAttr>() || NewD->hasAttr<CUDADeviceAttr>() || NewD->hasAttr<CUDAGlobalAttr>()) return; // Is D a __device__ function with the same signature as NewD, ignoring CUDA // attributes? auto IsMatchingDeviceFn = [&](NamedDecl *D) { if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(D)) D = Using->getTargetDecl(); FunctionDecl *OldD = D->getAsFunction(); return OldD && OldD->hasAttr<CUDADeviceAttr>() && !OldD->hasAttr<CUDAHostAttr>() && !IsOverload(NewD, OldD, /* UseMemberUsingDeclRules = */ false, /* ConsiderCudaAttrs = */ false); }; auto It = llvm::find_if(Previous, IsMatchingDeviceFn); if (It != Previous.end()) { // We found a __device__ function with the same name and signature as NewD // (ignoring CUDA attrs). This is an error unless that function is defined // in a system header, in which case we simply return without making NewD // host+device. NamedDecl *Match = *It; if (!getSourceManager().isInSystemHeader(Match->getLocation())) { Diag(NewD->getLocation(), diag::err_cuda_unattributed_constexpr_cannot_overload_device) << NewD->getName(); Diag(Match->getLocation(), diag::note_cuda_conflicting_device_function_declared_here); } return; } NewD->addAttr(CUDAHostAttr::CreateImplicit(Context)); NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context)); }
// Returns true on failure. static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, //SourceRange BaseRange, const StructType *STy, SourceLocation OpLoc) { StructTypeDecl *SDecl = STy->getDecl(); DeclContext *DC = SDecl; // The record definition is complete, now look up the member. SemaRef.LookupQualifiedName(R, DC); if (!R.empty()) return false; #if 0 // We didn't find anything with the given name, so try to correct // for typos. DeclarationName Name = R.getLookupName(); RecordMemberExprValidatorCCC Validator; TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), NULL, &SS, Validator, DC); R.clear(); if (NamedDecl *ND = Corrected.getCorrectionDecl()) { std::string CorrectedStr( Corrected.getAsString(SemaRef.getLangOpts())); std::string CorrectedQuotedStr( Corrected.getQuoted(SemaRef.getLangOpts())); R.setLookupName(Corrected.getCorrection()); R.addDecl(ND); SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest) << Name << DC << CorrectedQuotedStr << SS.getRange() << FixItHint::CreateReplacement(Corrected.getCorrectionRange(), CorrectedStr); SemaRef.Diag(ND->getLocation(), diag::note_previous_decl) << ND->getDeclName(); } #endif // FIXME: Is this right? (also in clang) return false; }
bool CoroutineStmtBuilder::makeOnFallthrough() { assert(!IsPromiseDependentType && "cannot make statement while the promise type is dependent"); // [dcl.fct.def.coroutine]/4 // The unqualified-ids 'return_void' and 'return_value' are looked up in // the scope of class P. If both are found, the program is ill-formed. bool HasRVoid, HasRValue; LookupResult LRVoid = lookupMember(S, "return_void", PromiseRecordDecl, Loc, HasRVoid); LookupResult LRValue = lookupMember(S, "return_value", PromiseRecordDecl, Loc, HasRValue); StmtResult Fallthrough; if (HasRVoid && HasRValue) { // FIXME Improve this diagnostic S.Diag(FD.getLocation(), diag::err_coroutine_promise_incompatible_return_functions) << PromiseRecordDecl; S.Diag(LRVoid.getRepresentativeDecl()->getLocation(), diag::note_member_first_declared_here) << LRVoid.getLookupName(); S.Diag(LRValue.getRepresentativeDecl()->getLocation(), diag::note_member_first_declared_here) << LRValue.getLookupName(); return false; } else if (!HasRVoid && !HasRValue) { // FIXME: The PDTS currently specifies this case as UB, not ill-formed. // However we still diagnose this as an error since until the PDTS is fixed. S.Diag(FD.getLocation(), diag::err_coroutine_promise_requires_return_function) << PromiseRecordDecl; S.Diag(PromiseRecordDecl->getLocation(), diag::note_defined_here) << PromiseRecordDecl; return false; } else if (HasRVoid) { // If the unqualified-id return_void is found, flowing off the end of a // coroutine is equivalent to a co_return with no operand. Otherwise, // flowing off the end of a coroutine results in undefined behavior. Fallthrough = S.BuildCoreturnStmt(FD.getLocation(), nullptr, /*IsImplicit*/false); Fallthrough = S.ActOnFinishFullStmt(Fallthrough.get()); if (Fallthrough.isInvalid()) return false; } this->OnFallthrough = Fallthrough.get(); return true; }
/// Checks access to all the declarations in the given result set. void Sema::CheckLookupAccess(const LookupResult &R) { assert(getLangOptions().AccessControl && "performing access check without access control"); assert(R.getNamingClass() && "performing access check without naming class"); for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { if (I.getAccess() != AS_public) { AccessTarget Entity(Context, AccessedEntity::Member, R.getNamingClass(), I.getPair(), R.getBaseObjectType()); Entity.setDiag(diag::err_access); CheckAccess(*this, R.getNameLoc(), Entity); } } }
void InterpretedIC::replace(LookupResult result, klassOop receiver_klass) { // IC entries before modification - used for loging only Bytecodes::Code code_before = send_code(); oop word1_before = first_word(); oop word2_before = second_word(); int transition = 0; // modify IC guarantee(word2_before == receiver_klass, "klass should be the same"); if (result.is_empty()) { clear(); transition = 1; } else if (result.is_method()) { if (send_type() == Bytecodes::megamorphic_send) { set(send_code(), result.method(), receiver_klass); transition = 2; } else { // Please Fix this Robert // implement set_monomorphic(klass, method) clear(); transition = 3; } } else { if (send_type() == Bytecodes::megamorphic_send) { set(send_code(), oop(result.entry()), receiver_klass); transition = 4; } else { assert(result.is_entry(), "must be jump table entry"); // a jump table entry of a nmethod is found so let's update the current send set(Bytecodes::compiled_send_code_for(send_code()), oop(result.entry()), receiver_klass); transition = 5; } } // IC entries after modification - used for loging only Bytecodes::Code code_after = send_code(); oop word1_after = first_word(); oop word2_after = second_word(); // log modification LOG_EVENT3("InterpretedIC::replace: IC at 0x%x: entry for klass 0x%x replaced (transition %d)", this, receiver_klass, transition); LOG_EVENT3(" from (%s, 0x%x, 0x%x)", Bytecodes::name(code_before), word1_before, word2_before); LOG_EVENT3(" to (%s, 0x%x, 0x%x)", Bytecodes::name(code_after ), word1_after , word2_after ); }
VectorImage::Draw(gfxContext* aContext, const nsIntSize& aSize, const ImageRegion& aRegion, uint32_t aWhichFrame, Filter aFilter, const Maybe<SVGImageContext>& aSVGContext, uint32_t aFlags) { if (aWhichFrame > FRAME_MAX_VALUE) { return DrawResult::BAD_ARGS; } if (!aContext) { return DrawResult::BAD_ARGS; } if (mError) { return DrawResult::BAD_IMAGE; } if (!mIsFullyLoaded) { return DrawResult::NOT_READY; } if (mIsDrawing) { NS_WARNING("Refusing to make re-entrant call to VectorImage::Draw"); return DrawResult::TEMPORARY_ERROR; } if (mAnimationConsumers == 0 && mProgressTracker) { mProgressTracker->OnUnlockedDraw(); } AutoRestore<bool> autoRestoreIsDrawing(mIsDrawing); mIsDrawing = true; Maybe<SVGImageContext> svgContext; // If FLAG_FORCE_PRESERVEASPECTRATIO_NONE bit is set, that mean we should // overwrite SVG preserveAspectRatio attibute of this image with none, and // always stretch this image to viewport non-uniformly. // And we can do this only if the caller pass in the the SVG viewport, via // aSVGContext. if ((aFlags & FLAG_FORCE_PRESERVEASPECTRATIO_NONE) && aSVGContext.isSome()) { Maybe<SVGPreserveAspectRatio> aspectRatio = Some(SVGPreserveAspectRatio(SVG_PRESERVEASPECTRATIO_NONE, SVG_MEETORSLICE_UNKNOWN)); svgContext = Some(SVGImageContext(aSVGContext->GetViewportSize(), aspectRatio)); } else { svgContext = aSVGContext; } float animTime = (aWhichFrame == FRAME_FIRST) ? 0.0f : mSVGDocumentWrapper->GetCurrentTime(); AutoSVGRenderingState autoSVGState(svgContext, animTime, mSVGDocumentWrapper->GetRootSVGElem()); SVGDrawingParameters params(aContext, aSize, aRegion, aFilter, svgContext, animTime, aFlags); if (aFlags & FLAG_BYPASS_SURFACE_CACHE) { CreateSurfaceAndShow(params); return DrawResult::SUCCESS; } LookupResult result = SurfaceCache::Lookup(ImageKey(this), VectorSurfaceKey(params.size, params.svgContext, params.animationTime)); // Draw. if (result) { RefPtr<SourceSurface> surface = result.DrawableRef()->GetSurface(); if (surface) { RefPtr<gfxDrawable> svgDrawable = new gfxSurfaceDrawable(surface, result.DrawableRef()->GetSize()); Show(svgDrawable, params); return DrawResult::SUCCESS; } // We lost our surface due to some catastrophic event. RecoverFromLossOfSurfaces(); } CreateSurfaceAndShow(params); return DrawResult::SUCCESS; }
Optional<Type> TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, ObjCKeyPathExpr *expr, bool requireResultType) { // If there is already a semantic expression, do nothing. if (expr->getSemanticExpr() && !requireResultType) return None; // #keyPath only makes sense when we have the Objective-C runtime. if (!Context.LangOpts.EnableObjCInterop) { diagnose(expr->getLoc(), diag::expr_keypath_no_objc_runtime); expr->setSemanticExpr( new (Context) StringLiteralExpr("", expr->getSourceRange(), /*Implicit=*/true)); return None; } // The key path string we're forming. SmallString<32> keyPathScratch; llvm::raw_svector_ostream keyPathOS(keyPathScratch); // Captures the state of semantic resolution. enum State { Beginning, ResolvingType, ResolvingProperty, ResolvingArray, ResolvingSet, ResolvingDictionary, } state = Beginning; /// Determine whether we are currently resolving a property. auto isResolvingProperty = [&] { switch (state) { case Beginning: case ResolvingType: return false; case ResolvingProperty: case ResolvingArray: case ResolvingSet: case ResolvingDictionary: return true; } }; // The type of AnyObject, which is used whenever we don't have // sufficient type information. Type anyObjectType; if (auto anyObject = Context.getProtocol(KnownProtocolKind::AnyObject)) { validateDecl(anyObject); anyObjectType = anyObject->getDeclaredInterfaceType(); } else { diagnose(expr->getLoc(), diag::stdlib_anyobject_not_found); return None; } // Local function to update the state after we've resolved a // component. Type currentType; auto updateState = [&](bool isProperty, Type newType) { // Strip off optionals. newType = newType->lookThroughAllAnyOptionalTypes(); // If updating to a type, just set the new type; there's nothing // more to do. if (!isProperty) { assert(state == Beginning || state == ResolvingType); state = ResolvingType; currentType = newType; return; } // We're updating to a property. Determine whether we're looking // into a bridged Swift collection of some sort. if (auto boundGeneric = newType->getAs<BoundGenericType>()) { auto nominal = boundGeneric->getDecl(); // Array<T> if (nominal == Context.getArrayDecl()) { // Further lookups into the element type. state = ResolvingArray; currentType = boundGeneric->getGenericArgs()[0]; return; } // Set<T> if (nominal == Context.getSetDecl()) { // Further lookups into the element type. state = ResolvingSet; currentType = boundGeneric->getGenericArgs()[0]; return; } // Dictionary<K, V> if (nominal == Context.getDictionaryDecl()) { // Key paths look into the keys of a dictionary; further // lookups into the value type. state = ResolvingDictionary; currentType = boundGeneric->getGenericArgs()[1]; return; } } // Determine whether we're looking into a Foundation collection. if (auto classDecl = newType->getClassOrBoundGenericClass()) { if (classDecl->isObjC() && classDecl->hasClangNode()) { SmallString<32> scratch; StringRef objcClassName = classDecl->getObjCRuntimeName(scratch); // NSArray if (objcClassName == "NSArray") { // The element type is unknown, so use AnyObject. state = ResolvingArray; currentType = anyObjectType; return; } // NSSet if (objcClassName == "NSSet") { // The element type is unknown, so use AnyObject. state = ResolvingSet; currentType = anyObjectType; return; } // NSDictionary if (objcClassName == "NSDictionary") { // Key paths look into the keys of a dictionary; there's no // type to help us here. state = ResolvingDictionary; currentType = anyObjectType; return; } } } // It's just a property. state = ResolvingProperty; currentType = newType; }; // Local function to perform name lookup for the current index. auto performLookup = [&](unsigned idx, Identifier componentName, SourceLoc componentNameLoc) -> LookupResult { if (state == Beginning) return lookupUnqualified(dc, componentName, componentNameLoc); assert(currentType && "Non-beginning state must have a type"); // Determine the type in which the lookup should occur. If we have // a bridged value type, this will be the Objective-C class to // which it is bridged. Type lookupType; if (auto bridgedClass = Context.getBridgedToObjC(dc, currentType)) lookupType = bridgedClass; else lookupType = currentType; // Look for a member with the given name within this type. return lookupMember(dc, lookupType, componentName); }; // Local function to print a component to the string. bool needDot = false; auto printComponent = [&](Identifier component) { if (needDot) keyPathOS << "."; else needDot = true; keyPathOS << component.str(); }; bool isInvalid = false; for (unsigned idx : range(expr->getNumComponents())) { auto componentName = expr->getComponentName(idx); auto componentNameLoc = expr->getComponentNameLoc(idx); // If we are resolving into a dictionary, any component is // well-formed because the keys are unknown dynamically. if (state == ResolvingDictionary) { // Just print the component unchanged; there's no checking we // can do here. printComponent(componentName); // From here, we're resolving a property. Use the current type. updateState(/*isProperty=*/true, currentType); continue; } // Look for this component. LookupResult lookup = performLookup(idx, componentName, componentNameLoc); // If we didn't find anything, try to apply typo-correction. bool resultsAreFromTypoCorrection = false; if (!lookup) { performTypoCorrection(dc, DeclRefKind::Ordinary, currentType, componentName, componentNameLoc, (currentType ? defaultMemberTypeLookupOptions : defaultUnqualifiedLookupOptions), lookup); if (currentType) diagnose(componentNameLoc, diag::could_not_find_type_member, currentType, componentName); else diagnose(componentNameLoc, diag::use_unresolved_identifier, componentName, false); // Note all the correction candidates. for (auto &result : lookup) { noteTypoCorrection(componentName, DeclNameLoc(componentNameLoc), result); } isInvalid = true; if (!lookup) break; // Remember that these are from typo correction. resultsAreFromTypoCorrection = true; } // If we have more than one result, filter out unavailable or // obviously unusable candidates. if (lookup.size() > 1) { lookup.filter([&](LookupResult::Result result) -> bool { // Drop unavailable candidates. if (result->getAttrs().isUnavailable(Context)) return false; // Drop non-property, non-type candidates. if (!isa<VarDecl>(result.Decl) && !isa<TypeDecl>(result.Decl)) return false; return true; }); } // If we *still* have more than one result, fail. if (lookup.size() > 1) { // Don't diagnose ambiguities if the results are from typo correction. if (resultsAreFromTypoCorrection) break; if (currentType) diagnose(componentNameLoc, diag::ambiguous_member_overload_set, componentName); else diagnose(componentNameLoc, diag::ambiguous_decl_ref, componentName); for (auto result : lookup) { diagnose(result, diag::decl_declared_here, result->getFullName()); } isInvalid = true; break; } auto found = lookup.front().Decl; // Handle property references. if (auto var = dyn_cast<VarDecl>(found)) { validateDecl(var); // Resolve this component to the variable we found. expr->resolveComponent(idx, var); updateState(/*isProperty=*/true, var->getType()->getRValueObjectType()); // Check that the property is @objc. if (!var->isObjC()) { diagnose(componentNameLoc, diag::expr_keypath_non_objc_property, componentName); if (var->getLoc().isValid() && var->getDeclContext()->isTypeContext()) { diagnose(var, diag::make_decl_objc, var->getDescriptiveKind()) .fixItInsert(var->getAttributeInsertionLoc(false), "@objc "); } } else { // FIXME: Warn about non-KVC-compliant getter/setter names? } // Print the Objective-C property name. printComponent(var->getObjCPropertyName()); continue; } // Handle type references. if (auto type = dyn_cast<TypeDecl>(found)) { // We cannot refer to a type via a property. if (isResolvingProperty()) { diagnose(componentNameLoc, diag::expr_keypath_type_of_property, componentName, currentType); isInvalid = true; break; } // We cannot refer to a generic type. if (type->getDeclaredInterfaceType()->hasTypeParameter()) { diagnose(componentNameLoc, diag::expr_keypath_generic_type, componentName); isInvalid = true; break; } Type newType; if (currentType && !currentType->isAnyObject()) { newType = currentType->getTypeOfMember(dc->getParentModule(), type, this); } else { newType = type->getDeclaredInterfaceType(); } if (!newType) { isInvalid = true; break; } updateState(/*isProperty=*/false, newType); continue; } // Declarations that cannot be part of a key-path. diagnose(componentNameLoc, diag::expr_keypath_not_property, found->getDescriptiveKind(), found->getFullName()); isInvalid = true; break; } // Check for an empty key-path string. auto keyPathString = keyPathOS.str(); if (keyPathString.empty() && !isInvalid) diagnose(expr->getLoc(), diag::expr_keypath_empty); // Set the semantic expression. if (!expr->getSemanticExpr()) { expr->setSemanticExpr( new (Context) StringLiteralExpr(Context.AllocateCopy(keyPathString), expr->getSourceRange(), /*Implicit=*/true)); } if (!currentType) return None; return currentType; }
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; }
LookupResult TypeChecker::lookupMember(DeclContext *dc, Type type, DeclName name, NameLookupOptions options) { LookupResult result; NLOptions subOptions = NL_QualifiedDefault; if (options.contains(NameLookupFlags::KnownPrivate)) subOptions |= NL_KnownNonCascadingDependency; if (options.contains(NameLookupFlags::DynamicLookup)) subOptions |= NL_DynamicLookup; if (options.contains(NameLookupFlags::IgnoreAccessibility)) subOptions |= NL_IgnoreAccessibility; // Dig out the type that we'll actually be looking into, and determine // whether it is a nominal type. Type lookupType = type; if (auto lvalueType = lookupType->getAs<LValueType>()) { lookupType = lvalueType->getObjectType(); } if (auto metaType = lookupType->getAs<MetatypeType>()) { lookupType = metaType->getInstanceType(); } NominalTypeDecl *nominalLookupType = lookupType->getAnyNominal(); /// Whether to consider protocol members or not. bool considerProtocolMembers = nominalLookupType && !isa<ProtocolDecl>(nominalLookupType) && options.contains(NameLookupFlags::ProtocolMembers); if (considerProtocolMembers) subOptions |= NL_ProtocolMembers; // We handle our own overriding/shadowing filtering. subOptions &= ~NL_RemoveOverridden; subOptions &= ~NL_RemoveNonVisible; // We can't have tuple types here; they need to be handled elsewhere. assert(!type->is<TupleType>()); // Local function that performs lookup. auto doLookup = [&]() { result.clear(); LookupResultBuilder builder(*this, result, dc, options, considerProtocolMembers, false); SmallVector<ValueDecl *, 4> lookupResults; dc->lookupQualified(type, name, subOptions, this, lookupResults); for (auto found : lookupResults) { builder.add(found, nominalLookupType, type); } }; doLookup(); if (result.empty()) { // If we didn't find anything, /and/ this is a nominal type, check to see // if any of the nominal's protocols are derivable and contain the // name we're looking for. (Note that we are not including extensions // here -- default derivation doesn't apply in extensions.) if (!nominalLookupType) return result; // Force the creation of any delayed members, to ensure proper member // lookup. this->forceExternalDeclMembers(nominalLookupType); // Perform the lookup again. // FIXME: This is only because forceExternalDeclMembers() might do something // interesting. doLookup(); } return result; }