#include "TypeLocBuilder.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "llvm/ADT/STLExtras.h"
using namespace clang;
static CXXRecordDecl *getCurrentInstantiationOf(QualType T,
DeclContext *CurContext) {
if (T.isNull())
return nullptr;
const Type *Ty = T->getCanonicalTypeInternal().getTypePtr();
if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl());
if (!Record->isDependentContext() ||
Record->isCurrentInstantiation(CurContext))
return Record;
return nullptr;
} else if (isa<InjectedClassNameType>(Ty))
return cast<InjectedClassNameType>(Ty)->getDecl();
else
return nullptr;
}
DeclContext *Sema::computeDeclContext(QualType T) {
if (!T->isDependentType())
if (const TagType *Tag = T->getAs<TagType>())
return Tag->getDecl();
return ::getCurrentInstantiationOf(T, CurContext);
}
DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
bool EnteringContext) {
if (!SS.isSet() || SS.isInvalid())
return nullptr;
NestedNameSpecifier *NNS = SS.getScopeRep();
if (NNS->isDependent()) {
if (CXXRecordDecl *Record = getCurrentInstantiationOf(NNS))
return Record;
if (EnteringContext) {
const Type *NNSType = NNS->getAsType();
if (!NNSType) {
return nullptr;
}
NNSType = Context.getCanonicalType(NNSType);
if (const TemplateSpecializationType *SpecType
= NNSType->getAs<TemplateSpecializationType>()) {
if (ClassTemplateDecl *ClassTemplate
= dyn_cast_or_null<ClassTemplateDecl>(
SpecType->getTemplateName().getAsTemplateDecl())) {
QualType ContextType
= Context.getCanonicalType(QualType(SpecType, 0));
QualType Injected
= ClassTemplate->getInjectedClassNameSpecialization();
if (Context.hasSameType(Injected, ContextType))
return ClassTemplate->getTemplatedDecl();
if (ClassTemplatePartialSpecializationDecl *PartialSpec
= ClassTemplate->findPartialSpecialization(ContextType)) {
assert(!isSFINAEContext() &&
"partial specialization scope specifier in SFINAE context?");
if (!hasReachableDefinition(PartialSpec))
diagnoseMissingImport(SS.getLastQualifierNameLoc(), PartialSpec,
MissingImportKind::PartialSpecialization,
true);
return PartialSpec;
}
}
} else if (const RecordType *RecordT = NNSType->getAs<RecordType>()) {
return RecordT->getDecl();
}
}
return nullptr;
}
switch (NNS->getKind()) {
case NestedNameSpecifier::Identifier:
llvm_unreachable("Dependent nested-name-specifier has no DeclContext");
case NestedNameSpecifier::Namespace:
return NNS->getAsNamespace();
case NestedNameSpecifier::NamespaceAlias:
return NNS->getAsNamespaceAlias()->getNamespace();
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
const TagType *Tag = NNS->getAsType()->getAs<TagType>();
assert(Tag && "Non-tag type in nested-name-specifier");
return Tag->getDecl();
}
case NestedNameSpecifier::Global:
return Context.getTranslationUnitDecl();
case NestedNameSpecifier::Super:
return NNS->getAsRecordDecl();
}
llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
}
bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) {
if (!SS.isSet() || SS.isInvalid())
return false;
return SS.getScopeRep()->isDependent();
}
CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
assert(getLangOpts().CPlusPlus && "Only callable in C++");
assert(NNS->isDependent() && "Only dependent nested-name-specifier allowed");
if (!NNS->getAsType())
return nullptr;
QualType T = QualType(NNS->getAsType(), 0);
return ::getCurrentInstantiationOf(T, CurContext);
}
bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
DeclContext *DC) {
assert(DC && "given null context");
TagDecl *tag = dyn_cast<TagDecl>(DC);
if (!tag || tag->isDependentContext())
return false;
QualType type = Context.getTypeDeclType(tag);
tag = type->getAsTagDecl();
if (tag->isBeingDefined())
return false;
SourceLocation loc = SS.getLastQualifierNameLoc();
if (loc.isInvalid()) loc = SS.getRange().getBegin();
if (RequireCompleteType(loc, type, diag::err_incomplete_nested_name_spec,
SS.getRange())) {
SS.SetInvalid(SS.getRange());
return true;
}
if (auto *EnumD = dyn_cast<EnumDecl>(tag))
return RequireCompleteEnumDecl(EnumD, loc, &SS);
return false;
}
bool Sema::RequireCompleteEnumDecl(EnumDecl *EnumD, SourceLocation L,
CXXScopeSpec *SS) {
if (EnumD->isCompleteDefinition()) {
NamedDecl *SuggestedDef = nullptr;
if (!hasReachableDefinition(EnumD, &SuggestedDef,
false)) {
bool TreatAsComplete = !isSFINAEContext();
diagnoseMissingImport(L, SuggestedDef, MissingImportKind::Definition,
TreatAsComplete);
return !TreatAsComplete;
}
return false;
}
if (EnumDecl *Pattern = EnumD->getInstantiatedFromMemberEnum()) {
MemberSpecializationInfo *MSI = EnumD->getMemberSpecializationInfo();
if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) {
if (InstantiateEnum(L, EnumD, Pattern,
getTemplateInstantiationArgs(EnumD),
TSK_ImplicitInstantiation)) {
if (SS)
SS->SetInvalid(SS->getRange());
return true;
}
return false;
}
}
if (SS) {
Diag(L, diag::err_incomplete_nested_name_spec)
<< QualType(EnumD->getTypeForDecl(), 0) << SS->getRange();
SS->SetInvalid(SS->getRange());
} else {
Diag(L, diag::err_incomplete_enum) << QualType(EnumD->getTypeForDecl(), 0);
Diag(EnumD->getLocation(), diag::note_declared_at);
}
return true;
}
bool Sema::ActOnCXXGlobalScopeSpecifier(SourceLocation CCLoc,
CXXScopeSpec &SS) {
SS.MakeGlobal(Context, CCLoc);
return false;
}
bool Sema::ActOnSuperScopeSpecifier(SourceLocation SuperLoc,
SourceLocation ColonColonLoc,
CXXScopeSpec &SS) {
CXXRecordDecl *RD = nullptr;
for (Scope *S = getCurScope(); S; S = S->getParent()) {
if (S->isFunctionScope()) {
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(S->getEntity()))
RD = MD->getParent();
break;
}
if (S->isClassScope()) {
RD = cast<CXXRecordDecl>(S->getEntity());
break;
}
}
if (!RD) {
Diag(SuperLoc, diag::err_invalid_super_scope);
return true;
} else if (RD->isLambda()) {
Diag(SuperLoc, diag::err_super_in_lambda_unsupported);
return true;
} else if (RD->getNumBases() == 0) {
Diag(SuperLoc, diag::err_no_base_classes) << RD->getName();
return true;
}
SS.MakeSuper(Context, RD, SuperLoc, ColonColonLoc);
return false;
}
bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD,
bool *IsExtension) {
if (!SD)
return false;
SD = SD->getUnderlyingDecl();
if (isa<NamespaceDecl>(SD))
return true;
if (!isa<TypeDecl>(SD))
return false;
QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
if (T->isDependentType())
return true;
if (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) {
if (TD->getUnderlyingType()->isRecordType())
return true;
if (TD->getUnderlyingType()->isEnumeralType()) {
if (Context.getLangOpts().CPlusPlus11)
return true;
if (IsExtension)
*IsExtension = true;
}
} else if (isa<RecordDecl>(SD)) {
return true;
} else if (isa<EnumDecl>(SD)) {
if (Context.getLangOpts().CPlusPlus11)
return true;
if (IsExtension)
*IsExtension = true;
}
return false;
}
NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
if (!S || !NNS)
return nullptr;
while (NNS->getPrefix())
NNS = NNS->getPrefix();
if (NNS->getKind() != NestedNameSpecifier::Identifier)
return nullptr;
LookupResult Found(*this, NNS->getAsIdentifier(), SourceLocation(),
LookupNestedNameSpecifierName);
LookupName(Found, S);
assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet");
if (!Found.isSingleResult())
return nullptr;
NamedDecl *Result = Found.getFoundDecl();
if (isAcceptableNestedNameSpecifier(Result))
return Result;
return nullptr;
}
bool Sema::isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS,
NestedNameSpecInfo &IdInfo) {
QualType ObjectType = GetTypeFromParser(IdInfo.ObjectType);
LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc,
LookupNestedNameSpecifierName);
DeclContext *LookupCtx = nullptr;
bool isDependent = false;
if (!ObjectType.isNull()) {
assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
LookupCtx = computeDeclContext(ObjectType);
isDependent = ObjectType->isDependentType();
} else if (SS.isSet()) {
LookupCtx = computeDeclContext(SS, false);
isDependent = isDependentScopeSpecifier(SS);
Found.setContextRange(SS.getRange());
}
if (LookupCtx) {
if (!LookupCtx->isDependentContext() &&
RequireCompleteDeclContext(SS, LookupCtx))
return false;
LookupQualifiedName(Found, LookupCtx);
} else if (isDependent) {
return false;
} else {
LookupName(Found, S);
}
Found.suppressDiagnostics();
return Found.getAsSingle<NamespaceDecl>();
}
namespace {
class NestedNameSpecifierValidatorCCC final
: public CorrectionCandidateCallback {
public:
explicit NestedNameSpecifierValidatorCCC(Sema &SRef)
: SRef(SRef) {}
bool ValidateCandidate(const TypoCorrection &candidate) override {
return SRef.isAcceptableNestedNameSpecifier(candidate.getCorrectionDecl());
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
return std::make_unique<NestedNameSpecifierValidatorCCC>(*this);
}
private:
Sema &SRef;
};
}
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);
DeclContext *LookupCtx = nullptr;
bool isDependent = false;
if (IsCorrectedToColon)
*IsCorrectedToColon = false;
if (!ObjectType.isNull()) {
assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
LookupCtx = computeDeclContext(ObjectType);
isDependent = ObjectType->isDependentType();
} else if (SS.isSet()) {
LookupCtx = computeDeclContext(SS, EnteringContext);
isDependent = isDependentScopeSpecifier(SS);
Found.setContextRange(SS.getRange());
}
bool ObjectTypeSearchedInScope = false;
if (LookupCtx) {
if (!LookupCtx->isDependentContext() &&
RequireCompleteDeclContext(SS, LookupCtx))
return true;
LookupQualifiedName(Found, LookupCtx);
if (!ObjectType.isNull() && Found.empty()) {
if (S)
LookupName(Found, S);
else if (ScopeLookupResult)
Found.addDecl(ScopeLookupResult);
ObjectTypeSearchedInScope = true;
}
} else if (!isDependent) {
LookupName(Found, S);
}
if (Found.isAmbiguous())
return true;
if (Found.empty() && isDependent &&
!(LookupCtx && LookupCtx->isRecord() &&
(!cast<CXXRecordDecl>(LookupCtx)->hasDefinition() ||
!cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()))) {
if (ErrorRecoveryLookup)
return true;
SS.Extend(Context, IdInfo.Identifier, IdInfo.IdentifierLoc, IdInfo.CCLoc);
return false;
}
if (Found.empty() && !ErrorRecoveryLookup) {
LookupResult R(*this, Found.getLookupNameInfo(), LookupOrdinaryName);
if (LookupCtx)
LookupQualifiedName(R, LookupCtx);
else if (S && !isDependent)
LookupName(R, S);
if (!R.empty()) {
R.suppressDiagnostics();
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;
}
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) {
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) {
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);
}
}
if (auto *TD = dyn_cast_or_null<TypedefNameDecl>(SD))
MarkAnyDeclReferenced(TD->getLocation(), TD, false);
if (ErrorRecoveryLookup)
return false;
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()));
if (T->isEnumeralType())
Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec);
TypeLocBuilder TLB;
if (const auto *USD = dyn_cast<UsingShadowDecl>(SD)) {
T = Context.getUsingType(USD, T);
TLB.pushTypeSpec(T).setNameLoc(IdInfo.IdentifierLoc);
} else 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");
}
SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T),
IdInfo.CCLoc);
return false;
}
if (ErrorRecoveryLookup)
return true;
if (Found.empty()) {
Found.clear(LookupOrdinaryName);
LookupName(Found, S);
}
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 if (Found.getAsSingle<TemplateDecl>()) {
ParsedType SuggestedType;
DiagnoseUnknownTypeName(IdInfo.Identifier, IdInfo.IdentifierLoc, S, &SS,
SuggestedType);
} 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;
}
bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
bool EnteringContext, CXXScopeSpec &SS,
bool *IsCorrectedToColon,
bool OnlyNamespace) {
if (SS.isInvalid())
return true;
return BuildCXXNestedNameSpecifier(S, IdInfo, EnteringContext, SS,
nullptr, false,
IsCorrectedToColon, OnlyNamespace);
}
bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
const DeclSpec &DS,
SourceLocation ColonColonLoc) {
if (SS.isInvalid() || DS.getTypeSpecType() == DeclSpec::TST_error)
return true;
assert(DS.getTypeSpecType() == DeclSpec::TST_decltype);
QualType T = BuildDecltypeType(DS.getRepAsExpr());
if (T.isNull())
return true;
if (!T->isDependentType() && !T->getAs<TagType>()) {
Diag(DS.getTypeSpecTypeLoc(), diag::err_expected_class_or_namespace)
<< T << getLangOpts().CPlusPlus;
return true;
}
TypeLocBuilder TLB;
DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc());
DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd());
SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T),
ColonColonLoc);
return false;
}
bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS,
NestedNameSpecInfo &IdInfo,
bool EnteringContext) {
if (SS.isInvalid())
return false;
return !BuildCXXNestedNameSpecifier(S, IdInfo, EnteringContext, SS,
nullptr, true);
}
bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
TemplateTy OpaqueTemplate,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
SourceLocation RAngleLoc,
SourceLocation CCLoc,
bool EnteringContext) {
if (SS.isInvalid())
return true;
TemplateName Template = OpaqueTemplate.get();
TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
translateTemplateArguments(TemplateArgsIn, TemplateArgs);
DependentTemplateName *DTN = Template.getAsDependentTemplateName();
if (DTN && DTN->isIdentifier()) {
assert(DTN->getQualifier() == SS.getScopeRep());
QualType T = Context.getDependentTemplateSpecializationType(ETK_None,
DTN->getQualifier(),
DTN->getIdentifier(),
TemplateArgs);
TypeLocBuilder Builder;
DependentTemplateSpecializationTypeLoc SpecTL
= Builder.push<DependentTemplateSpecializationTypeLoc>(T);
SpecTL.setElaboratedKeywordLoc(SourceLocation());
SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
SpecTL.setTemplateNameLoc(TemplateNameLoc);
SpecTL.setLAngleLoc(LAngleLoc);
SpecTL.setRAngleLoc(RAngleLoc);
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
SS.Extend(Context, TemplateKWLoc, Builder.getTypeLocInContext(Context, T),
CCLoc);
return false;
}
if (Template.getAsAssumedTemplateName() &&
resolveAssumedTemplateNameAsType(S, Template, TemplateNameLoc))
return true;
TemplateDecl *TD = Template.getAsTemplateDecl();
if (Template.getAsOverloadedTemplate() || DTN ||
isa<FunctionTemplateDecl>(TD) || isa<VarTemplateDecl>(TD)) {
SourceRange R(TemplateNameLoc, RAngleLoc);
if (SS.getRange().isValid())
R.setBegin(SS.getRange().getBegin());
Diag(CCLoc, diag::err_non_type_template_in_nested_name_specifier)
<< (TD && isa<VarTemplateDecl>(TD)) << Template << R;
NoteAllFoundTemplates(Template);
return true;
}
QualType T = CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs);
if (T.isNull())
return true;
if (!T->isDependentType() && !T->getAs<TagType>()) {
Diag(TemplateNameLoc, diag::err_nested_name_spec_non_tag) << T;
NoteAllFoundTemplates(Template);
return true;
}
TypeLocBuilder Builder;
TemplateSpecializationTypeLoc SpecTL
= Builder.push<TemplateSpecializationTypeLoc>(T);
SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
SpecTL.setTemplateNameLoc(TemplateNameLoc);
SpecTL.setLAngleLoc(LAngleLoc);
SpecTL.setRAngleLoc(RAngleLoc);
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
SS.Extend(Context, TemplateKWLoc, Builder.getTypeLocInContext(Context, T),
CCLoc);
return false;
}
namespace {
struct NestedNameSpecifierAnnotation {
NestedNameSpecifier *NNS;
};
}
void *Sema::SaveNestedNameSpecifierAnnotation(CXXScopeSpec &SS) {
if (SS.isEmpty() || SS.isInvalid())
return nullptr;
void *Mem = Context.Allocate(
(sizeof(NestedNameSpecifierAnnotation) + SS.location_size()),
alignof(NestedNameSpecifierAnnotation));
NestedNameSpecifierAnnotation *Annotation
= new (Mem) NestedNameSpecifierAnnotation;
Annotation->NNS = SS.getScopeRep();
memcpy(Annotation + 1, SS.location_data(), SS.location_size());
return Annotation;
}
void Sema::RestoreNestedNameSpecifierAnnotation(void *AnnotationPtr,
SourceRange AnnotationRange,
CXXScopeSpec &SS) {
if (!AnnotationPtr) {
SS.SetInvalid(AnnotationRange);
return;
}
NestedNameSpecifierAnnotation *Annotation
= static_cast<NestedNameSpecifierAnnotation *>(AnnotationPtr);
SS.Adopt(NestedNameSpecifierLoc(Annotation->NNS, Annotation + 1));
}
bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
if (isa<ObjCContainerDecl>(CurContext) || isa<ObjCMethodDecl>(CurContext))
return false;
NestedNameSpecifier *Qualifier = SS.getScopeRep();
switch (Qualifier->getKind()) {
case NestedNameSpecifier::Global:
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
return CurContext->getRedeclContext()->isFileContext();
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::Super:
return true;
}
llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
}
bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
if (SS.isInvalid()) return true;
DeclContext *DC = computeDeclContext(SS, true);
if (!DC) return true;
if (!DC->isDependentContext() && RequireCompleteDeclContext(SS, DC))
return true;
EnterDeclaratorContext(S, DC);
if (DC->isDependentContext())
RebuildNestedNameSpecifierInCurrentInstantiation(SS);
return false;
}
void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
if (SS.isInvalid())
return;
assert(!SS.isInvalid() && computeDeclContext(SS, true) &&
"exiting declarator scope we never really entered");
ExitDeclaratorContext(S);
}