DeclContext *DeclContext::getLookupContext() { DeclContext *Ctx = this; // Skip through transparent contexts. while (Ctx->isTransparentContext()) Ctx = Ctx->getParent(); return Ctx; }
Decl *DeclContext::getInnermostDeclarationDeclContext() { DeclContext *DC = this; while (DC) { switch (DC->getContextKind()) { case DeclContextKind::AbstractClosureExpr: case DeclContextKind::Initializer: case DeclContextKind::SerializedLocal: case DeclContextKind::Module: case DeclContextKind::FileUnit: break; case DeclContextKind::TopLevelCodeDecl: return cast<TopLevelCodeDecl>(DC); case DeclContextKind::AbstractFunctionDecl: return cast<AbstractFunctionDecl>(DC); case DeclContextKind::SubscriptDecl: return cast<SubscriptDecl>(DC); case DeclContextKind::NominalTypeDecl: return cast<NominalTypeDecl>(DC); case DeclContextKind::ExtensionDecl: return cast<ExtensionDecl>(DC); } DC = DC->getParent(); } return nullptr; }
DeclContext *DeclContext::getEnclosingNamespaceContext() { DeclContext *Ctx = this; // Skip through non-namespace, non-translation-unit contexts. while (!Ctx->isFileContext() || Ctx->isTransparentContext()) Ctx = Ctx->getParent(); return Ctx->getPrimaryContext(); }
DeclContext *Sema::getFunctionLevelDeclContext() { DeclContext *DC = CurContext; while (true) { if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC)) { DC = DC->getParent(); } else if (isa<CXXMethodDecl>(DC) && cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call && cast<CXXRecordDecl>(DC->getParent())->isLambda()) { DC = DC->getParent()->getParent(); } else break; } return DC; }
AbstractFunctionDecl *DeclContext::getInnermostMethodContext() { DeclContext *result = this; while (true) { switch (result->getContextKind()) { case DeclContextKind::AbstractClosureExpr: case DeclContextKind::Initializer: case DeclContextKind::SerializedLocal: // Look through closures, initial values. result = result->getParent(); continue; case DeclContextKind::AbstractFunctionDecl: { // If this function is a method, we found our result. auto func = dyn_cast<AbstractFunctionDecl>(result); if (func->getDeclContext()->isTypeContext()) return func; // This function isn't a method; look through it. result = func->getDeclContext(); continue; } case DeclContextKind::ExtensionDecl: case DeclContextKind::FileUnit: case DeclContextKind::Module: case DeclContextKind::NominalTypeDecl: case DeclContextKind::TopLevelCodeDecl: case DeclContextKind::SubscriptDecl: // Not in a method context. return nullptr; } } }
void SynthesizeRemovalConsumer::processDeclContext(DeclContext *DC) { for(auto I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { if (auto D = dyn_cast<ObjCMethodDecl>(*I)) { // handle methods if (auto B = D->getBody()) { processStmt(B, D); } } else if (auto D = dyn_cast<BlockDecl>(*I)) { // handle blocks in a method; find the parent context first DeclContext *P = D->getParent(); while (P) { if (dyn_cast<ObjCMethodDecl>(P)) { break; } P = P->getParent(); } // only when P is a ObjCMethodDecl can me proceed if (P) { if (auto B = D->getBody()) { processStmt(B, P); } } } // descend into the next level (for namespace, blocks, etc.) if (auto innerDC = dyn_cast<DeclContext>(*I)) { processDeclContext(innerDC); } } }
/// @brief Ensure that the type T is a complete type. /// /// This routine checks whether the type @p T is complete in any /// context where a complete type is required. If @p T is a complete /// type, returns false. If @p T is a class template specialization, /// this routine then attempts to perform class template /// instantiation. If instantiation fails, or if @p T is incomplete /// and cannot be completed, issues the diagnostic @p diag (giving it /// the type @p T) and returns true. /// /// @param Loc The location in the source that the incomplete type /// diagnostic should refer to. /// /// @param T The type that this routine is examining for completeness. /// /// @param diag The diagnostic value (e.g., /// @c diag::err_typecheck_decl_incomplete_type) that will be used /// for the error message if @p T is incomplete. /// /// @param Range1 An optional range in the source code that will be a /// part of the "incomplete type" error message. /// /// @param Range2 An optional range in the source code that will be a /// part of the "incomplete type" error message. /// /// @param PrintType If non-NULL, the type that should be printed /// instead of @p T. This parameter should be used when the type that /// we're checking for incompleteness isn't the type that should be /// displayed to the user, e.g., when T is a type and PrintType is a /// pointer to T. /// /// @returns @c true if @p T is incomplete and a diagnostic was emitted, /// @c false otherwise. bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag, SourceRange Range1, SourceRange Range2, QualType PrintType) { // If we have a complete type, we're done. if (!T->isIncompleteType()) return false; // If we have a class template specialization or a class member of a // class template specialization, try to instantiate it. if (const RecordType *Record = T->getAsRecordType()) { if (ClassTemplateSpecializationDecl *ClassTemplateSpec = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) { if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) { // Update the class template specialization's location to // refer to the point of instantiation. if (Loc.isValid()) ClassTemplateSpec->setLocation(Loc); return InstantiateClassTemplateSpecialization(ClassTemplateSpec, /*ExplicitInstantiation=*/false); } } else if (CXXRecordDecl *Rec = dyn_cast<CXXRecordDecl>(Record->getDecl())) { if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) { // Find the class template specialization that surrounds this // member class. ClassTemplateSpecializationDecl *Spec = 0; for (DeclContext *Parent = Rec->getDeclContext(); Parent && !Spec; Parent = Parent->getParent()) Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent); assert(Spec && "Not a member of a class template specialization?"); return InstantiateClass(Loc, Rec, Pattern, Spec->getTemplateArgs(), Spec->getNumTemplateArgs()); } } } if (PrintType.isNull()) PrintType = T; // We have an incomplete type. Produce a diagnostic. Diag(Loc, diag) << PrintType << Range1 << Range2; // If the type was a forward declaration of a class/struct/union // type, produce const TagType *Tag = 0; if (const RecordType *Record = T->getAsRecordType()) Tag = Record; else if (const EnumType *Enum = T->getAsEnumType()) Tag = Enum; if (Tag && !Tag->getDecl()->isInvalidDecl()) Diag(Tag->getDecl()->getLocation(), Tag->isBeingDefined() ? diag::note_type_being_defined : diag::note_forward_declaration) << QualType(Tag, 0); return true; }
DeclContext *Sema::getFunctionLevelDeclContext() { DeclContext *DC = CurContext; while (isa<BlockDecl>(DC)) DC = DC->getParent(); return DC; }
SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const { // Anonymous functions have shared linkage. // FIXME: This should really be the linkage of the parent function. if (getAbstractClosureExpr()) return SILLinkage::Shared; // 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 SILLinkage::Shared; moduleContext = moduleContext->getParent(); } // Currying and calling convention thunks have shared linkage. if (isThunk()) // 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; // Enum constructors are essentially the same as thunks, they are // emitted by need and have shared linkage. if (kind == Kind::EnumElement) return SILLinkage::Shared; // Declarations imported from Clang modules have shared linkage. const SILLinkage ClangLinkage = SILLinkage::Shared; if (isClangImported()) return ClangLinkage; // Declarations that were derived on behalf of types in Clang modules get // shared linkage. if (auto *FD = dyn_cast<FuncDecl>(d)) { if (auto derivedFor = FD->getDerivedForTypeDecl()) if (isa<ClangModuleUnit>(derivedFor->getModuleScopeContext())) return ClangLinkage; } // Otherwise, we have external linkage. switch (d->getEffectiveAccess()) { case Accessibility::Private: return (forDefinition ? SILLinkage::Private : SILLinkage::PrivateExternal); case Accessibility::Internal: return (forDefinition ? SILLinkage::Hidden : SILLinkage::HiddenExternal); default: return (forDefinition ? SILLinkage::Public : SILLinkage::PublicExternal); } }
bool EvaluateTSynthesizer::IsArtificiallyDependent(Expr* Node) { if (!Node->isValueDependent() || !Node->isTypeDependent()) return false; DeclContext* DC = m_CurDeclContext; while (DC) { if (DC->isDependentContext()) return false; DC = DC->getParent(); } return true; }
SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const { // Anonymous functions have shared linkage. // FIXME: This should really be the linkage of the parent function. if (getAbstractClosureExpr()) return SILLinkage::Shared; // 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 SILLinkage::Shared; moduleContext = moduleContext->getParent(); } // Currying and calling convention thunks have shared linkage. if (isThunk()) // 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; // Enum constructors are essentially the same as thunks, they are // emitted by need and have shared linkage. if (isEnumElement()) return SILLinkage::Shared; // Stored property initializers have hidden linkage, since they are // not meant to be used from outside of their module. if (isStoredPropertyInitializer()) return SILLinkage::Hidden; // Declarations imported from Clang modules have shared linkage. const SILLinkage ClangLinkage = SILLinkage::Shared; if (isClangImported()) return ClangLinkage; // Otherwise, we have external linkage. switch (d->getEffectiveAccess()) { case Accessibility::Private: case Accessibility::FilePrivate: return (forDefinition ? SILLinkage::Private : SILLinkage::PrivateExternal); case Accessibility::Internal: return (forDefinition ? SILLinkage::Hidden : SILLinkage::HiddenExternal); default: return (forDefinition ? SILLinkage::Public : SILLinkage::PublicExternal); } }
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; }
TranslationUnitDecl *Decl::getTranslationUnitDecl() { if (TranslationUnitDecl *TUD = dyn_cast<TranslationUnitDecl>(this)) return TUD; DeclContext *DC = getDeclContext(); assert(DC && "This decl is not contained in a translation unit!"); while (!DC->isTranslationUnit()) { DC = DC->getParent(); assert(DC && "This decl is not contained in a translation unit!"); } return cast<TranslationUnitDecl>(DC); }
//===----------------------------------------------------------------------===// // Inheritance clause handling //===----------------------------------------------------------------------===// static std::tuple<TypeResolutionOptions, DeclContext *, MutableArrayRef<TypeLoc>> decomposeInheritedClauseDecl( llvm::PointerUnion<TypeDecl *, ExtensionDecl *> decl) { TypeResolutionOptions options; DeclContext *dc; MutableArrayRef<TypeLoc> inheritanceClause; if (auto typeDecl = decl.dyn_cast<TypeDecl *>()) { inheritanceClause = typeDecl->getInherited(); if (auto nominal = dyn_cast<NominalTypeDecl>(typeDecl)) { dc = nominal; options |= TypeResolutionFlags::GenericSignature; options |= TypeResolutionFlags::InheritanceClause; options |= TypeResolutionFlags::AllowUnavailableProtocol; } else { dc = typeDecl->getDeclContext(); if (isa<GenericTypeParamDecl>(typeDecl)) { // For generic parameters, we want name lookup to look at just the // signature of the enclosing entity. if (auto nominal = dyn_cast<NominalTypeDecl>(dc)) { dc = nominal; options |= TypeResolutionFlags::GenericSignature; } else if (auto ext = dyn_cast<ExtensionDecl>(dc)) { dc = ext; options |= TypeResolutionFlags::GenericSignature; } else if (auto func = dyn_cast<AbstractFunctionDecl>(dc)) { dc = func; options |= TypeResolutionFlags::GenericSignature; } else if (!dc->isModuleScopeContext()) { // Skip the generic parameter's context entirely. dc = dc->getParent(); } } } } else { auto ext = decl.get<ExtensionDecl *>(); inheritanceClause = ext->getInherited(); dc = ext; options |= TypeResolutionFlags::GenericSignature; options |= TypeResolutionFlags::InheritanceClause; options |= TypeResolutionFlags::AllowUnavailableProtocol; } return std::make_tuple(options, dc, inheritanceClause); }
bool BlinkGCPluginConsumer::InCheckedNamespace(RecordInfo* info) { if (!info) return false; for (DeclContext* context = info->record()->getDeclContext(); !context->isTranslationUnit(); context = context->getParent()) { if (NamespaceDecl* decl = dyn_cast<NamespaceDecl>(context)) { if (decl->isAnonymousNamespace()) return true; if (options_.checked_namespaces.find(decl->getNameAsString()) != options_.checked_namespaces.end()) { return true; } } } return false; }
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; } } }
/// 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(); } }
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; } } }
/// 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; }
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"); }
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; }