-ms-extensions: Implement __super scope specifier (PR13236).
We build a NestedNameSpecifier that records the CXXRecordDecl in which
__super appeared. Name lookup is performed in all base classes of the
recorded CXXRecordDecl. Use of __super is allowed only inside class and
member function scope.
llvm-svn: 218484
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index 17dccc8..50ed49a 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -113,6 +113,18 @@
"NestedNameSpecifierLoc range computation incorrect");
}
+void CXXScopeSpec::MakeSuper(ASTContext &Context, CXXRecordDecl *RD,
+ SourceLocation SuperLoc,
+ SourceLocation ColonColonLoc) {
+ Builder.MakeSuper(Context, RD, SuperLoc, ColonColonLoc);
+
+ Range.setBegin(SuperLoc);
+ Range.setEnd(ColonColonLoc);
+
+ assert(Range == Builder.getSourceRange() &&
+ "NestedNameSpecifierLoc range computation incorrect");
+}
+
void CXXScopeSpec::MakeTrivial(ASTContext &Context,
NestedNameSpecifier *Qualifier, SourceRange R) {
Builder.MakeTrivial(Context, Qualifier, R);
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index d3f0fad..739cba7 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -148,6 +148,9 @@
case NestedNameSpecifier::Global:
return Context.getTranslationUnitDecl();
+
+ case NestedNameSpecifier::Super:
+ return NNS->getAsRecordDecl();
}
llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
@@ -240,12 +243,43 @@
return true;
}
-bool Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc,
+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;
+}
+
/// \brief Determines whether the given declaration is an valid acceptable
/// result for name lookup of a nested-name-specifier.
bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD) {
@@ -953,6 +987,7 @@
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
+ case NestedNameSpecifier::Super:
// These are never namespace scopes.
return true;
}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 1bac287..abbf4b2 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -498,6 +498,9 @@
/// @endcode
bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) {
if (CurContext->isRecord()) {
+ if (SS->getScopeRep()->getKind() == NestedNameSpecifier::Super)
+ return true;
+
const Type *Ty = SS->getScopeRep()->getAsType();
CXXRecordDecl *RD = cast<CXXRecordDecl>(CurContext);
@@ -699,7 +702,11 @@
}
LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
- LookupParsedName(Result, S, &SS, !CurMethod);
+ NestedNameSpecifier *NNS = SS.getScopeRep();
+ if (NNS && NNS->getKind() == NestedNameSpecifier::Super)
+ LookupInSuper(Result, NNS->getAsRecordDecl());
+ else
+ LookupParsedName(Result, S, &SS, !CurMethod);
// For unqualified lookup in a class template in MSVC mode, look into
// dependent base classes where the primary class template is known.
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index f938fd3..d79dcca 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -67,6 +67,7 @@
break;
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
llvm_unreachable("Nested name specifier is not a type for inheriting ctor");
@@ -354,6 +355,7 @@
return true;
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
return false;
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 54f9673..76e0ba1 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -1824,6 +1824,26 @@
return LookupName(R, S, AllowBuiltinCreation);
}
+/// \brief Perform qualified name lookup into all base classes of the given
+/// class.
+///
+/// \param R captures both the lookup criteria and any lookup results found.
+///
+/// \param Class The context in which qualified name lookup will
+/// search. Name lookup will search in all base classes merging the results.
+void Sema::LookupInSuper(LookupResult &R, CXXRecordDecl *Class) {
+ for (const auto &BaseSpec : Class->bases()) {
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(
+ BaseSpec.getType()->castAs<RecordType>()->getDecl());
+ LookupResult Result(*this, R.getLookupNameInfo(), R.getLookupKind());
+ Result.setBaseObjectType(Context.getRecordType(Class));
+ LookupQualifiedName(Result, RD);
+ for (auto *Decl : Result)
+ R.addDecl(Decl);
+ }
+
+ R.resolveKind();
+}
/// \brief Produce a diagnostic describing the ambiguity that resulted
/// from name lookup.
@@ -3296,6 +3316,7 @@
break;
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
return;
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 3c37a3e..b47ce68 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4127,6 +4127,7 @@
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
return false;
case NestedNameSpecifier::TypeSpec:
@@ -7900,7 +7901,11 @@
DeclarationName Name(&II);
LookupResult Result(*this, Name, IILoc, LookupOrdinaryName);
- LookupQualifiedName(Result, Ctx);
+ NestedNameSpecifier *NNS = SS.getScopeRep();
+ if (NNS->getKind() == NestedNameSpecifier::Super)
+ LookupInSuper(Result, NNS->getAsRecordDecl());
+ else
+ LookupQualifiedName(Result, Ctx);
unsigned DiagID = 0;
Decl *Referenced = nullptr;
switch (Result.getResultKind()) {
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 51f36fe..31d7f73 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -3021,6 +3021,7 @@
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
llvm_unreachable("Nested-name-specifier must name a type");
case NestedNameSpecifier::TypeSpec:
@@ -3717,6 +3718,7 @@
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
llvm_unreachable("Nested-name-specifier must name a type");
}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index af91ea9..687f164 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3100,6 +3100,14 @@
SS.MakeGlobal(SemaRef.Context, Q.getBeginLoc());
break;
+ case NestedNameSpecifier::Super: {
+ CXXRecordDecl *RD =
+ cast_or_null<CXXRecordDecl>(getDerived().TransformDecl(
+ SourceLocation(), QNNS->getAsRecordDecl()));
+ SS.MakeSuper(SemaRef.Context, RD, Q.getBeginLoc(), Q.getEndLoc());
+ break;
+ }
+
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::TypeSpec: {
TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType,