[clang] 46131aa - Revert "Reapply "[Clang][Sema] Fix crash when 'this' is used in a dependent class scope function template specialization that instantiates to a static member function (#87541)" (#88311)"
Mikhail Goncharov via cfe-commits
cfe-commits at lists.llvm.org
Sun Apr 14 23:44:17 PDT 2024
Author: Mikhail Goncharov
Date: 2024-04-15T08:41:32+02:00
New Revision: 46131aaf616c5cd97df0ec376a7e6ba475e1913c
URL: https://github.com/llvm/llvm-project/commit/46131aaf616c5cd97df0ec376a7e6ba475e1913c
DIFF: https://github.com/llvm/llvm-project/commit/46131aaf616c5cd97df0ec376a7e6ba475e1913c.diff
LOG: Revert "Reapply "[Clang][Sema] Fix crash when 'this' is used in a dependent class scope function template specialization that instantiates to a static member function (#87541)" (#88311)"
This reverts commit aa80f3ec48419a73aafcc2ff947c6dd1e3734481.
See
https://github.com/llvm/llvm-project/pull/88311#issuecomment-2052291140.
There is a fix forward proposed but I am reverting this commit to fix
trunk.
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaExprMember.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/lib/Sema/TreeTransform.h
clang/test/SemaTemplate/instantiate-using-decl.cpp
clang/test/SemaTemplate/ms-function-specialization-class-scope.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ade8f4e93d5a0c..de5fa99bff5dbe 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -529,8 +529,6 @@ Bug Fixes to C++ Support
- Fix an issue caused by not handling invalid cases when substituting into the parameter mapping of a constraint. Fixes (#GH86757).
- Fixed a bug that prevented member function templates of class templates declared with a deduced return type
from being explicitly specialized for a given implicit instantiation of the class template.
-- Fixed a crash when ``this`` is used in a dependent class scope function template specialization
- that instantiates to a static member function.
- Fix crash when inheriting from a cv-qualified type. Fixes:
(`#35603 <https://github.com/llvm/llvm-project/issues/35603>`_)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index c6e0332c3176b3..c6035445e90192 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -5452,8 +5452,7 @@ class Sema final : public SemaBase {
ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R,
bool NeedsADL,
- bool AcceptInvalidDecl = false,
- bool NeedUnresolved = false);
+ bool AcceptInvalidDecl = false);
ExprResult BuildDeclarationNameExpr(
const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D,
NamedDecl *FoundD = nullptr,
@@ -6596,10 +6595,7 @@ class Sema final : public SemaBase {
SourceLocation RParenLoc);
//// ActOnCXXThis - Parse 'this' pointer.
- ExprResult ActOnCXXThis(SourceLocation Loc);
-
- /// Check whether the type of 'this' is valid in the current context.
- bool CheckCXXThisType(SourceLocation Loc, QualType Type);
+ ExprResult ActOnCXXThis(SourceLocation loc);
/// Build a CXXThisExpr and mark it referenced in the current context.
Expr *BuildCXXThisExpr(SourceLocation Loc, QualType Type, bool IsImplicit);
@@ -7022,14 +7018,10 @@ class Sema final : public SemaBase {
///@{
public:
- /// Check whether an expression might be an implicit class member access.
- bool isPotentialImplicitMemberAccess(const CXXScopeSpec &SS, LookupResult &R,
- bool IsAddressOfOperand);
-
ExprResult BuildPossibleImplicitMemberExpr(
const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs, const Scope *S);
-
+ const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
+ UnresolvedLookupExpr *AsULE = nullptr);
ExprResult
BuildImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
LookupResult &R,
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 505d068ac42ebe..c5395fb2068a18 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2917,9 +2917,26 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// to get this right here so that we don't end up making a
// spuriously dependent expression if we're inside a dependent
// instance method.
- if (isPotentialImplicitMemberAccess(SS, R, IsAddressOfOperand))
- return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs,
- S);
+ if (getLangOpts().CPlusPlus && !R.empty() &&
+ (*R.begin())->isCXXClassMember()) {
+ bool MightBeImplicitMember;
+ if (!IsAddressOfOperand)
+ MightBeImplicitMember = true;
+ else if (!SS.isEmpty())
+ MightBeImplicitMember = false;
+ else if (R.isOverloadedResult())
+ MightBeImplicitMember = false;
+ else if (R.isUnresolvableResult())
+ MightBeImplicitMember = true;
+ else
+ MightBeImplicitMember = isa<FieldDecl>(R.getFoundDecl()) ||
+ isa<IndirectFieldDecl>(R.getFoundDecl()) ||
+ isa<MSPropertyDecl>(R.getFoundDecl());
+
+ if (MightBeImplicitMember)
+ return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc,
+ R, TemplateArgs, S);
+ }
if (TemplateArgs || TemplateKWLoc.isValid()) {
@@ -3430,11 +3447,10 @@ static bool ShouldLookupResultBeMultiVersionOverload(const LookupResult &R) {
ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
LookupResult &R, bool NeedsADL,
- bool AcceptInvalidDecl,
- bool NeedUnresolved) {
+ bool AcceptInvalidDecl) {
// If this is a single, fully-resolved result and we don't need ADL,
// just build an ordinary singleton decl ref.
- if (!NeedUnresolved && !NeedsADL && R.isSingleResult() &&
+ if (!NeedsADL && R.isSingleResult() &&
!R.getAsSingle<FunctionTemplateDecl>() &&
!ShouldLookupResultBeMultiVersionOverload(R))
return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(),
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 25f23a3abf1718..fa7b92a43346b1 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1416,42 +1416,26 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit,
}
ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
- // C++20 [expr.prim.this]p1:
- // The keyword this names a pointer to the object for which an
- // implicit object member function is invoked or a non-static
- // data member's initializer is evaluated.
+ /// C++ 9.3.2: In the body of a non-static member function, the keyword this
+ /// is a non-lvalue expression whose value is the address of the object for
+ /// which the function is called.
QualType ThisTy = getCurrentThisType();
- if (CheckCXXThisType(Loc, ThisTy))
- return ExprError();
+ if (ThisTy.isNull()) {
+ DeclContext *DC = getFunctionLevelDeclContext();
- return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false);
-}
+ if (const auto *Method = dyn_cast<CXXMethodDecl>(DC);
+ Method && Method->isExplicitObjectMemberFunction()) {
+ return Diag(Loc, diag::err_invalid_this_use) << 1;
+ }
-bool Sema::CheckCXXThisType(SourceLocation Loc, QualType Type) {
- if (!Type.isNull())
- return false;
+ if (isLambdaCallWithExplicitObjectParameter(CurContext))
+ return Diag(Loc, diag::err_invalid_this_use) << 1;
- // C++20 [expr.prim.this]p3:
- // If a declaration declares a member function or member function template
- // of a class X, the expression this is a prvalue of type
- // "pointer to cv-qualifier-seq X" wherever X is the current class between
- // the optional cv-qualifier-seq and the end of the function-definition,
- // member-declarator, or declarator. It shall not appear within the
- // declaration of either a static member function or an explicit object
- // member function of the current class (although its type and value
- // category are defined within such member functions as they are within
- // an implicit object member function).
- DeclContext *DC = getFunctionLevelDeclContext();
- if (const auto *Method = dyn_cast<CXXMethodDecl>(DC);
- Method && Method->isExplicitObjectMemberFunction()) {
- Diag(Loc, diag::err_invalid_this_use) << 1;
- } else if (isLambdaCallWithExplicitObjectParameter(CurContext)) {
- Diag(Loc, diag::err_invalid_this_use) << 1;
- } else {
- Diag(Loc, diag::err_invalid_this_use) << 0;
+ return Diag(Loc, diag::err_invalid_this_use) << 0;
}
- return true;
+
+ return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false);
}
Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type,
@@ -8658,8 +8642,21 @@ static ExprResult attemptRecovery(Sema &SemaRef,
// Detect and handle the case where the decl might be an implicit
// member.
- if (SemaRef.isPotentialImplicitMemberAccess(
- NewSS, R, Consumer.isAddressOfOperand()))
+ bool MightBeImplicitMember;
+ if (!Consumer.isAddressOfOperand())
+ MightBeImplicitMember = true;
+ else if (!NewSS.isEmpty())
+ MightBeImplicitMember = false;
+ else if (R.isOverloadedResult())
+ MightBeImplicitMember = false;
+ else if (R.isUnresolvableResult())
+ MightBeImplicitMember = true;
+ else
+ MightBeImplicitMember = isa<FieldDecl>(ND) ||
+ isa<IndirectFieldDecl>(ND) ||
+ isa<MSPropertyDecl>(ND);
+
+ if (MightBeImplicitMember)
return SemaRef.BuildPossibleImplicitMemberExpr(
NewSS, /*TemplateKWLoc*/ SourceLocation(), R,
/*TemplateArgs*/ nullptr, /*S*/ nullptr);
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index eeac753a348979..32998ae60eafe2 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -61,10 +61,6 @@ enum IMAKind {
/// The reference is a contextually-permitted abstract member reference.
IMA_Abstract,
- /// Whether the context is static is dependent on the enclosing template (i.e.
- /// in a dependent class scope explicit specialization).
- IMA_Dependent,
-
/// The reference may be to an unresolved using declaration and the
/// context is not an instance method.
IMA_Unresolved_StaticOrExplicitContext,
@@ -95,18 +91,10 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
- bool couldInstantiateToStatic = false;
- bool isStaticOrExplicitContext = SemaRef.CXXThisTypeOverride.isNull();
-
- if (auto *MD = dyn_cast<CXXMethodDecl>(DC)) {
- if (MD->isImplicitObjectMemberFunction()) {
- isStaticOrExplicitContext = false;
- // A dependent class scope function template explicit specialization
- // that is neither declared 'static' nor with an explicit object
- // parameter could instantiate to a static or non-static member function.
- couldInstantiateToStatic = MD->getDependentSpecializationInfo();
- }
- }
+ bool isStaticOrExplicitContext =
+ SemaRef.CXXThisTypeOverride.isNull() &&
+ (!isa<CXXMethodDecl>(DC) || cast<CXXMethodDecl>(DC)->isStatic() ||
+ cast<CXXMethodDecl>(DC)->isExplicitObjectMemberFunction());
if (R.isUnresolvableResult())
return isStaticOrExplicitContext ? IMA_Unresolved_StaticOrExplicitContext
@@ -135,9 +123,6 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
if (Classes.empty())
return IMA_Static;
- if (couldInstantiateToStatic)
- return IMA_Dependent;
-
// C++11 [expr.prim.general]p12:
// An id-expression that denotes a non-static data member or non-static
// member function of a class can only be used:
@@ -278,52 +263,32 @@ static void diagnoseInstanceReference(Sema &SemaRef,
}
}
-bool Sema::isPotentialImplicitMemberAccess(const CXXScopeSpec &SS,
- LookupResult &R,
- bool IsAddressOfOperand) {
- if (!getLangOpts().CPlusPlus)
- return false;
- else if (R.empty() || !R.begin()->isCXXClassMember())
- return false;
- else if (!IsAddressOfOperand)
- return true;
- else if (!SS.isEmpty())
- return false;
- else if (R.isOverloadedResult())
- return false;
- else if (R.isUnresolvableResult())
- return true;
- else
- return isa<FieldDecl, IndirectFieldDecl, MSPropertyDecl>(R.getFoundDecl());
-}
-
/// Builds an expression which might be an implicit member expression.
ExprResult Sema::BuildPossibleImplicitMemberExpr(
const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs, const Scope *S) {
- switch (IMAKind Classification = ClassifyImplicitMemberAccess(*this, R)) {
+ const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
+ UnresolvedLookupExpr *AsULE) {
+ switch (ClassifyImplicitMemberAccess(*this, R)) {
case IMA_Instance:
+ return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true, S);
+
case IMA_Mixed:
case IMA_Mixed_Unrelated:
case IMA_Unresolved:
- return BuildImplicitMemberExpr(
- SS, TemplateKWLoc, R, TemplateArgs,
- /*IsKnownInstance=*/Classification == IMA_Instance, S);
+ return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, false,
+ S);
+
case IMA_Field_Uneval_Context:
Diag(R.getNameLoc(), diag::warn_cxx98_compat_non_static_member_use)
<< R.getLookupNameInfo().getName();
[[fallthrough]];
case IMA_Static:
case IMA_Abstract:
- case IMA_Dependent:
case IMA_Mixed_StaticOrExplicitContext:
case IMA_Unresolved_StaticOrExplicitContext:
if (TemplateArgs || TemplateKWLoc.isValid())
- return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*RequiresADL=*/false,
- TemplateArgs);
- return BuildDeclarationNameExpr(
- SS, R, /*NeedsADL=*/false, /*AcceptInvalidDecl=*/false,
- /*NeedUnresolved=*/Classification == IMA_Dependent);
+ return BuildTemplateIdExpr(SS, TemplateKWLoc, R, false, TemplateArgs);
+ return AsULE ? AsULE : BuildDeclarationNameExpr(SS, R, false);
case IMA_Error_StaticOrExplicitContext:
case IMA_Error_Unrelated:
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 21a139e434cb73..02d0b35ce940f1 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5097,14 +5097,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
EnterExpressionEvaluationContext EvalContext(
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
- Qualifiers ThisTypeQuals;
- CXXRecordDecl *ThisContext = nullptr;
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
- ThisContext = Method->getParent();
- ThisTypeQuals = Method->getMethodQualifiers();
- }
- CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals);
-
// Introduce a new scope where local variable instantiations will be
// recorded, unless we're actually a member function within a local
// class, in which case we need to merge our results with the parent
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index ee6bd228b459e2..fdf84c512c4931 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -795,9 +795,6 @@ class TreeTransform {
ParenExpr *PE, DependentScopeDeclRefExpr *DRE, bool IsAddressOfOperand,
TypeSourceInfo **RecoveryTSI);
- ExprResult TransformUnresolvedLookupExpr(UnresolvedLookupExpr *E,
- bool IsAddressOfOperand);
-
StmtResult TransformOMPExecutableDirective(OMPExecutableDirective *S);
// FIXME: We use LLVM_ATTRIBUTE_NOINLINE because inlining causes a ridiculous
@@ -3312,13 +3309,12 @@ class TreeTransform {
/// Build a new C++ "this" expression.
///
- /// By default, performs semantic analysis to build a new "this" expression.
- /// Subclasses may override this routine to provide
diff erent behavior.
+ /// By default, builds a new "this" expression without performing any
+ /// semantic analysis. Subclasses may override this routine to provide
+ ///
diff erent behavior.
ExprResult RebuildCXXThisExpr(SourceLocation ThisLoc,
QualType ThisType,
bool isImplicit) {
- if (getSema().CheckCXXThisType(ThisLoc, ThisType))
- return ExprError();
return getSema().BuildCXXThisExpr(ThisLoc, ThisType, isImplicit);
}
@@ -11369,11 +11365,7 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformAddressOfOperand(Expr *E) {
if (DependentScopeDeclRefExpr *DRE = dyn_cast<DependentScopeDeclRefExpr>(E))
- return getDerived().TransformDependentScopeDeclRefExpr(
- DRE, /*IsAddressOfOperand=*/true, nullptr);
- else if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E))
- return getDerived().TransformUnresolvedLookupExpr(
- ULE, /*IsAddressOfOperand=*/true);
+ return getDerived().TransformDependentScopeDeclRefExpr(DRE, true, nullptr);
else
return getDerived().TransformExpr(E);
}
@@ -13079,16 +13071,10 @@ bool TreeTransform<Derived>::TransformOverloadExprDecls(OverloadExpr *Old,
return false;
}
-template <typename Derived>
-ExprResult TreeTransform<Derived>::TransformUnresolvedLookupExpr(
- UnresolvedLookupExpr *Old) {
- return TransformUnresolvedLookupExpr(Old, /*IsAddressOfOperand=*/false);
-}
-
-template <typename Derived>
+template<typename Derived>
ExprResult
-TreeTransform<Derived>::TransformUnresolvedLookupExpr(UnresolvedLookupExpr *Old,
- bool IsAddressOfOperand) {
+TreeTransform<Derived>::TransformUnresolvedLookupExpr(
+ UnresolvedLookupExpr *Old) {
LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(),
Sema::LookupOrdinaryName);
@@ -13120,8 +13106,26 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(UnresolvedLookupExpr *Old,
R.setNamingClass(NamingClass);
}
- // Rebuild the template arguments, if any.
SourceLocation TemplateKWLoc = Old->getTemplateKeywordLoc();
+
+ // If we have neither explicit template arguments, nor the template keyword,
+ // it's a normal declaration name or member reference.
+ if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid()) {
+ NamedDecl *D = R.getAsSingle<NamedDecl>();
+ // In a C++11 unevaluated context, an UnresolvedLookupExpr might refer to an
+ // instance member. In other contexts, BuildPossibleImplicitMemberExpr will
+ // give a good diagnostic.
+ if (D && D->isCXXInstanceMember()) {
+ return SemaRef.BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R,
+ /*TemplateArgs=*/nullptr,
+ /*Scope=*/nullptr);
+ }
+
+ return getDerived().RebuildDeclarationNameExpr(SS, R, Old->requiresADL());
+ }
+
+ // If we have template arguments, rebuild them, then rebuild the
+ // templateid expression.
TemplateArgumentListInfo TransArgs(Old->getLAngleLoc(), Old->getRAngleLoc());
if (Old->hasExplicitTemplateArgs() &&
getDerived().TransformTemplateArguments(Old->getTemplateArgs(),
@@ -13131,23 +13135,6 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(UnresolvedLookupExpr *Old,
return ExprError();
}
- // An UnresolvedLookupExpr can refer to a class member. This occurs e.g. when
- // a non-static data member is named in an unevaluated operand, or when
- // a member is named in a dependent class scope function template explicit
- // specialization that is neither declared static nor with an explicit object
- // parameter.
- if (SemaRef.isPotentialImplicitMemberAccess(SS, R, IsAddressOfOperand))
- return SemaRef.BuildPossibleImplicitMemberExpr(
- SS, TemplateKWLoc, R,
- Old->hasExplicitTemplateArgs() ? &TransArgs : nullptr,
- /*S=*/nullptr);
-
- // If we have neither explicit template arguments, nor the template keyword,
- // it's a normal declaration name or member reference.
- if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid())
- return getDerived().RebuildDeclarationNameExpr(SS, R, Old->requiresADL());
-
- // If we have template arguments, then rebuild the template-id expression.
return getDerived().RebuildTemplateIdExpr(SS, TemplateKWLoc, R,
Old->requiresADL(), &TransArgs);
}
diff --git a/clang/test/SemaTemplate/instantiate-using-decl.cpp b/clang/test/SemaTemplate/instantiate-using-decl.cpp
index 28d83764385131..0bbb3ca9c88c8b 100644
--- a/clang/test/SemaTemplate/instantiate-using-decl.cpp
+++ b/clang/test/SemaTemplate/instantiate-using-decl.cpp
@@ -121,7 +121,7 @@ template <typename Scalar> struct Derived : Base<Scalar> {
(void)&field;
// expected-error at +1 {{call to non-static member function without an object argument}}
(void)method;
- // expected-error at +1 {{must explicitly qualify name of member function when taking its address}}
+ // expected-error at +1 {{call to non-static member function without an object argument}}
(void)&method;
// expected-error at +1 {{call to non-static member function without an object argument}}
method();
diff --git a/clang/test/SemaTemplate/ms-function-specialization-class-scope.cpp b/clang/test/SemaTemplate/ms-function-specialization-class-scope.cpp
index f7b59f2ac71586..dcab9bfaeabcb0 100644
--- a/clang/test/SemaTemplate/ms-function-specialization-class-scope.cpp
+++ b/clang/test/SemaTemplate/ms-function-specialization-class-scope.cpp
@@ -1,6 +1,7 @@
-// RUN: %clang_cc1 -fms-extensions -fsyntax-only -Wno-unused-value -verify %s
-// RUN: %clang_cc1 -fms-extensions -fdelayed-template-parsing -fsyntax-only -Wno-unused-value -verify %s
+// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fms-extensions -fdelayed-template-parsing -fsyntax-only -verify %s
+// expected-no-diagnostics
class A {
public:
template<class U> A(U p) {}
@@ -75,104 +76,3 @@ struct S {
int f<0>(int);
};
}
-
-namespace UsesThis {
- template<typename T>
- struct A {
- int x;
-
- static inline int y;
-
- template<typename U = void>
- static void f();
-
- template<typename U = void>
- void g();
-
- template<typename U>
- static auto h() -> A*;
-
- void i();
-
- static void j();
-
- template<>
- void f<int>() {
- this->x; // expected-error {{invalid use of 'this' outside of a non-static member function}}
- x; // expected-error {{invalid use of member 'x' in static member function}}
- A::x; // expected-error {{invalid use of member 'x' in static member function}}
- +x; // expected-error {{invalid use of member 'x' in static member function}}
- +A::x; // expected-error {{invalid use of member 'x' in static member function}}
- &x; // expected-error {{invalid use of member 'x' in static member function}}
- &A::x;
- this->y; // expected-error {{invalid use of 'this' outside of a non-static member function}}
- y;
- A::y;
- +y;
- +A::y;
- &y;
- &A::y;
- f();
- f<void>();
- g(); // expected-error {{call to non-static member function without an object argument}}
- g<void>(); // expected-error {{call to non-static member function without an object argument}}
- i(); // expected-error {{call to non-static member function without an object argument}}
- j();
- &i; // expected-error 2{{must explicitly qualify name of member function when taking its address}}
- &j;
- &A::i;
- &A::j;
- }
-
- template<>
- void g<int>() {
- this->x;
- x;
- A::x;
- +x;
- +A::x;
- &x;
- &A::x;
- this->y;
- y;
- A::y;
- +y;
- +A::y;
- &y;
- &A::y;
- f();
- f<void>();
- g();
- g<void>();
- i();
- j();
- &i; // expected-error 2{{must explicitly qualify name of member function when taking its address}}
- &j;
- &A::i;
- &A::j;
- }
-
- template<>
- auto h<int>() -> decltype(this); // expected-error {{'this' cannot be used in a static member function declaration}}
- };
-
- template struct A<int>; // expected-note 3{{in instantiation of}}
-
- template <typename T>
- struct Foo {
- template <typename X>
- int bar(X x) {
- return 0;
- }
-
- template <>
- int bar(int x) {
- return bar(5.0); // ok
- }
- };
-
- void call() {
- Foo<double> f;
- f.bar(1);
- }
-}
More information about the cfe-commits
mailing list