[clang] 0c6e1ca - Revert "[Clang][Sema] Diagnose class member access expressions naming non-existent members of the current instantiation prior to instantiation in the absence of dependent base classes (#84050)"
Pranav Kant via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 25 17:18:57 PDT 2024
Author: Pranav Kant
Date: 2024-04-26T00:18:08Z
New Revision: 0c6e1ca1c704a3a0fb53ae54f7e3723736f477c7
URL: https://github.com/llvm/llvm-project/commit/0c6e1ca1c704a3a0fb53ae54f7e3723736f477c7
DIFF: https://github.com/llvm/llvm-project/commit/0c6e1ca1c704a3a0fb53ae54f7e3723736f477c7.diff
LOG: Revert "[Clang][Sema] Diagnose class member access expressions naming non-existent members of the current instantiation prior to instantiation in the absence of dependent base classes (#84050)"
This reverts commit a8fd0d029dca7d17eee72d0445223c2fe1ee7758.
Added:
Modified:
clang-tools-extra/clangd/unittests/FindTargetTests.cpp
clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp
clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp
clang/docs/ReleaseNotes.rst
clang/include/clang/Sema/Lookup.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/Expr.cpp
clang/lib/Parse/ParseDecl.cpp
clang/lib/Sema/HLSLExternalSemaSource.cpp
clang/lib/Sema/SemaAttr.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaExprMember.cpp
clang/lib/Sema/SemaLookup.cpp
clang/lib/Sema/SemaOpenMP.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/TreeTransform.h
clang/test/AST/HLSL/this-reference-template.hlsl
clang/test/CXX/drs/dr2xx.cpp
clang/test/CXX/drs/dr3xx.cpp
clang/test/CXX/temp/temp.res/temp.local/p3.cpp
clang/test/CodeGenCXX/mangle.cpp
clang/test/Index/annotate-nested-name-specifier.cpp
clang/test/SemaCXX/member-expr.cpp
clang/test/SemaTemplate/instantiate-function-1.cpp
clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
Removed:
clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
################################################################################
diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
index 94437857cecca6..799a549ff0816e 100644
--- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -854,7 +854,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
}
};
)cpp";
- EXPECT_DECLS("MemberExpr", "void foo()");
+ EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
// Similar to above but base expression involves a function call.
Code = R"cpp(
@@ -872,7 +872,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
}
};
)cpp";
- EXPECT_DECLS("MemberExpr", "void foo()");
+ EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
// Similar to above but uses a function pointer.
Code = R"cpp(
@@ -891,7 +891,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
}
};
)cpp";
- EXPECT_DECLS("MemberExpr", "void foo()");
+ EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
// Base expression involves a member access into this.
Code = R"cpp(
@@ -962,7 +962,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
void Foo() { this->[[find]](); }
};
)cpp";
- EXPECT_DECLS("MemberExpr", "void find()");
+ EXPECT_DECLS("CXXDependentScopeMemberExpr", "void find()");
}
TEST_F(TargetDeclTest, DependentTypes) {
diff --git a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
index 30b9b1902aa9c7..4156921d83edf8 100644
--- a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
@@ -621,7 +621,7 @@ sizeof...($TemplateParameter[[Elements]]);
struct $Class_def[[Foo]] {
int $Field_decl[[Waldo]];
void $Method_def[[bar]]() {
- $Class[[Foo]]().$Field[[Waldo]];
+ $Class[[Foo]]().$Field_dependentName[[Waldo]];
}
template $Bracket[[<]]typename $TemplateParameter_def[[U]]$Bracket[[>]]
void $Method_def[[bar1]]() {
diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp
index ae61b17ca14d20..574efe7bd91478 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp
@@ -309,8 +309,6 @@ struct HeapArray { // Ok, since destruc
HeapArray(HeapArray &&other) : _data(other._data), size(other.size) { // Ok
other._data = nullptr; // Ok
- // CHECK-NOTES: [[@LINE-1]]:5: warning: expected assignment source to be of type 'gsl::owner<>'; got 'std::nullptr_t'
- // FIXME: This warning is emitted because an ImplicitCastExpr for the NullToPointer conversion isn't created for dependent types.
other.size = 0;
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp
index 4abb9c8555970e..559031cf4d9bda 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp
@@ -260,8 +260,6 @@ template <class T>
struct Template {
Template() = default;
Template(const Template &Other) : Field(Other.Field) {}
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
- // CHECK-FIXES: Template(const Template &Other) = default;
Template &operator=(const Template &Other);
void foo(const T &t);
int Field;
@@ -271,12 +269,8 @@ Template<T> &Template<T>::operator=(const Template<T> &Other) {
Field = Other.Field;
return *this;
}
-// CHECK-MESSAGES: :[[@LINE-4]]:27: warning: use '= default'
-// CHECK-FIXES: Template<T> &Template<T>::operator=(const Template<T> &Other) = default;
-
Template<int> T1;
-
// Dependent types.
template <class T>
struct DT1 {
@@ -290,9 +284,6 @@ DT1<T> &DT1<T>::operator=(const DT1<T> &Other) {
Field = Other.Field;
return *this;
}
-// CHECK-MESSAGES: :[[@LINE-4]]:17: warning: use '= default'
-// CHECK-FIXES: DT1<T> &DT1<T>::operator=(const DT1<T> &Other) = default;
-
DT1<int> Dt1;
template <class T>
@@ -312,9 +303,6 @@ DT2<T> &DT2<T>::operator=(const DT2<T> &Other) {
struct T {
typedef int TT;
};
-// CHECK-MESSAGES: :[[@LINE-8]]:17: warning: use '= default'
-// CHECK-FIXES: DT2<T> &DT2<T>::operator=(const DT2<T> &Other) = default;
-
DT2<T> Dt2;
// Default arguments.
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 00c684e773a2e0..f5e5d3a2e6ea36 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -385,18 +385,6 @@ Improvements to Clang's diagnostics
- Clang now diagnoses requires expressions with explicit object parameters.
-- Clang now looks up members of the current instantiation in the template definition context
- if the current instantiation has no dependent base classes.
-
- .. code-block:: c++
-
- template<typename T>
- struct A {
- int f() {
- return this->x; // error: no member named 'x' in 'A<T>'
- }
- };
-
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h
index b0a08a05ac6a0a..0db5b847038ffd 100644
--- a/clang/include/clang/Sema/Lookup.h
+++ b/clang/include/clang/Sema/Lookup.h
@@ -499,9 +499,7 @@ class LookupResult {
/// Note that while no result was found in the current instantiation,
/// there were dependent base classes that could not be searched.
void setNotFoundInCurrentInstantiation() {
- assert((ResultKind == NotFound ||
- ResultKind == NotFoundInCurrentInstantiation) &&
- Decls.empty());
+ assert(ResultKind == NotFound && Decls.empty());
ResultKind = NotFoundInCurrentInstantiation;
}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index aa182b15e66ecc..1ca523ec88c2f9 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7472,7 +7472,7 @@ class Sema final : public SemaBase {
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
CXXScopeSpec &SS);
bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
- QualType ObjectType, bool AllowBuiltinCreation = false,
+ bool AllowBuiltinCreation = false,
bool EnteringContext = false);
ObjCProtocolDecl *LookupProtocol(
IdentifierInfo *II, SourceLocation IdLoc,
@@ -8881,13 +8881,11 @@ class Sema final : public SemaBase {
/// functions (but no function templates).
FoundFunctions,
};
-
- bool
- LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
- QualType ObjectType, bool EnteringContext,
- RequiredTemplateKind RequiredTemplate = SourceLocation(),
- AssumedTemplateKind *ATK = nullptr,
- bool AllowTypoCorrection = true);
+ bool LookupTemplateName(
+ LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType,
+ bool EnteringContext, bool &MemberOfUnknownSpecialization,
+ RequiredTemplateKind RequiredTemplate = SourceLocation(),
+ AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true);
TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS,
bool hasTemplateKeyword,
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index d2e40be59d6f3b..63dcdb919c7117 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -103,7 +103,7 @@ const Expr *Expr::skipRValueSubobjectAdjustments(
}
} else if (const auto *ME = dyn_cast<MemberExpr>(E)) {
if (!ME->isArrow()) {
- assert(ME->getBase()->getType()->getAsRecordDecl());
+ assert(ME->getBase()->getType()->isRecordType());
if (const auto *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
if (!Field->isBitField() && !Field->getType()->isReferenceType()) {
E = ME->getBase();
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 53a33fa4add54e..05ad5ecbfaa0cf 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2998,7 +2998,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
<< TokenName << TagName << getLangOpts().CPlusPlus
<< FixItHint::CreateInsertion(Tok.getLocation(), FixitTagName);
- if (Actions.LookupName(R, getCurScope())) {
+ if (Actions.LookupParsedName(R, getCurScope(), SS)) {
for (LookupResult::iterator I = R.begin(), IEnd = R.end();
I != IEnd; ++I)
Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index bb283c54b3d29c..1a1febf7a35241 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -126,15 +126,12 @@ struct BuiltinTypeDeclBuilder {
static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S,
StringRef Name) {
+ CXXScopeSpec SS;
IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
DeclarationNameInfo NameInfo =
DeclarationNameInfo(DeclarationName(&II), SourceLocation());
LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
- // AllowBuiltinCreation is false but LookupDirect will create
- // the builtin when searching the global scope anyways...
- S.LookupName(R, S.getCurScope());
- // FIXME: If the builtin function was user-declared in global scope,
- // this assert *will* fail. Should this call LookupBuiltin instead?
+ S.LookupParsedName(R, S.getCurScope(), &SS, false);
assert(R.isSingleResult() &&
"Since this is a builtin it should always resolve!");
auto *VD = cast<ValueDecl>(R.getFoundDecl());
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index a83b1e8afadbc6..a5dd158808f26b 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -837,7 +837,7 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
IdentifierInfo *Name = IdTok.getIdentifierInfo();
LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName);
- LookupName(Lookup, curScope, /*AllowBuiltinCreation=*/true);
+ LookupParsedName(Lookup, curScope, nullptr, true);
if (Lookup.empty()) {
Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4e275dc15fbb4e..e0745fe9a45367 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -832,7 +832,7 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
IdentifierInfo *&Name,
SourceLocation NameLoc) {
LookupResult R(SemaRef, Name, NameLoc, Sema::LookupTagName);
- SemaRef.LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
+ SemaRef.LookupParsedName(R, S, &SS);
if (TagDecl *Tag = R.getAsSingle<TagDecl>()) {
StringRef FixItTagName;
switch (Tag->getTagKind()) {
@@ -869,7 +869,7 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
// Replace lookup results with just the tag decl.
Result.clear(Sema::LookupTagName);
- SemaRef.LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType());
+ SemaRef.LookupParsedName(Result, S, &SS);
return true;
}
@@ -896,8 +896,7 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
}
LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
- LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType(),
- /*AllowBuiltinCreation=*/!CurMethod);
+ LookupParsedName(Result, S, &SS, !CurMethod);
if (SS.isInvalid())
return NameClassification::Error();
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 4d5836720a651f..abdbc9d8830c03 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4517,7 +4517,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
DS.getBeginLoc(), DS.getEllipsisLoc());
} else {
LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName);
- LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
+ LookupParsedName(R, S, &SS);
TypeDecl *TyD = R.getAsSingle<TypeDecl>();
if (!TyD) {
@@ -12262,7 +12262,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc,
// Lookup namespace name.
LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName);
- LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
+ LookupParsedName(R, S, &SS);
if (R.isAmbiguous())
return nullptr;
@@ -13721,7 +13721,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,
// Lookup the namespace name.
LookupResult R(*this, Ident, IdentLoc, LookupNamespaceName);
- LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
+ LookupParsedName(R, S, &SS);
if (R.isAmbiguous())
return nullptr;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 0c37f43f75401b..50f92c496a539a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -673,9 +673,8 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
// expressions of certain types in C++.
if (getLangOpts().CPlusPlus &&
(E->getType() == Context.OverloadTy ||
- // FIXME: This is a hack! We want the lvalue-to-rvalue conversion applied
- // to pointer types even if the pointee type is dependent.
- (T->isDependentType() && !T->isPointerType()) || T->isRecordType()))
+ T->isDependentType() ||
+ T->isRecordType()))
return E;
// The C standard is actually really unclear on this point, and
@@ -2752,8 +2751,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
if (isBoundsAttrContext() && !getLangOpts().CPlusPlus && S->isClassScope()) {
// See if this is reference to a field of struct.
LookupResult R(*this, NameInfo, LookupMemberName);
- // LookupName handles a name lookup from within anonymous struct.
- if (LookupName(R, S)) {
+ // LookupParsedName handles a name lookup from within anonymous struct.
+ if (LookupParsedName(R, S, &SS)) {
if (auto *VD = dyn_cast<ValueDecl>(R.getFoundDecl())) {
QualType type = VD->getType().getNonReferenceType();
// This will eventually be translated into MemberExpr upon
@@ -2774,19 +2773,20 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// lookup to determine that it was a template name in the first place. If
// this becomes a performance hit, we can work harder to preserve those
// results until we get here but it's likely not worth it.
+ bool MemberOfUnknownSpecialization;
AssumedTemplateKind AssumedTemplate;
- if (LookupTemplateName(R, S, SS, /*ObjectType=*/QualType(),
- /*EnteringContext=*/false, TemplateKWLoc,
+ if (LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,
+ MemberOfUnknownSpecialization, TemplateKWLoc,
&AssumedTemplate))
return ExprError();
- if (R.wasNotFoundInCurrentInstantiation())
+ if (MemberOfUnknownSpecialization ||
+ (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation))
return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
IsAddressOfOperand, TemplateArgs);
} else {
bool IvarLookupFollowUp = II && !SS.isSet() && getCurMethodDecl();
- LookupParsedName(R, S, &SS, /*ObjectType=*/QualType(),
- /*AllowBuiltinCreation=*/!IvarLookupFollowUp);
+ LookupParsedName(R, S, &SS, !IvarLookupFollowUp);
// If the result might be in a dependent base class, this is a dependent
// id-expression.
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index c1cb03e4ec7ae2..779a41620033dc 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -9157,7 +9157,7 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S,
// Do the redeclaration lookup in the current scope.
LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName,
RedeclarationKind::NotForRedeclaration);
- LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
+ LookupParsedName(R, S, &SS);
R.suppressDiagnostics();
switch (R.getResultKind()) {
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 0eeb7b1faa0a22..6e30716b9ae436 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -667,8 +667,8 @@ namespace {
// classes, one of its base classes.
class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback {
public:
- explicit RecordMemberExprValidatorCCC(QualType RTy)
- : Record(RTy->getAsRecordDecl()) {
+ explicit RecordMemberExprValidatorCCC(const RecordType *RTy)
+ : Record(RTy->getDecl()) {
// Don't add bare keywords to the consumer since they will always fail
// validation by virtue of not being associated with any decls.
WantTypeSpecifiers = false;
@@ -713,36 +713,58 @@ class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback {
}
static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
- Expr *BaseExpr, QualType RTy,
+ Expr *BaseExpr,
+ const RecordType *RTy,
SourceLocation OpLoc, bool IsArrow,
CXXScopeSpec &SS, bool HasTemplateArgs,
SourceLocation TemplateKWLoc,
TypoExpr *&TE) {
SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange();
- if (!RTy->isDependentType() &&
- !SemaRef.isThisOutsideMemberFunctionBody(RTy) &&
- SemaRef.RequireCompleteType(
- OpLoc, RTy, diag::err_typecheck_incomplete_tag, BaseRange))
+ RecordDecl *RDecl = RTy->getDecl();
+ if (!SemaRef.isThisOutsideMemberFunctionBody(QualType(RTy, 0)) &&
+ SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
+ diag::err_typecheck_incomplete_tag,
+ BaseRange))
return true;
- // LookupTemplateName/LookupParsedName don't expect these both to exist
- // simultaneously.
- QualType ObjectType = SS.isSet() ? QualType() : RTy;
- if (HasTemplateArgs || TemplateKWLoc.isValid())
- return SemaRef.LookupTemplateName(R,
- /*S=*/nullptr, SS, ObjectType,
- /*EnteringContext=*/false, TemplateKWLoc);
+ if (HasTemplateArgs || TemplateKWLoc.isValid()) {
+ // LookupTemplateName doesn't expect these both to exist simultaneously.
+ QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0);
- SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType);
+ bool MOUS;
+ return SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS,
+ TemplateKWLoc);
+ }
+
+ DeclContext *DC = RDecl;
+ if (SS.isSet()) {
+ // If the member name was a qualified-id, look into the
+ // nested-name-specifier.
+ DC = SemaRef.computeDeclContext(SS, false);
+
+ if (SemaRef.RequireCompleteDeclContext(SS, DC)) {
+ SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
+ << SS.getRange() << DC;
+ return true;
+ }
+
+ assert(DC && "Cannot handle non-computable dependent contexts in lookup");
+
+ if (!isa<TypeDecl>(DC)) {
+ SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass)
+ << DC << SS.getRange();
+ return true;
+ }
+ }
- if (!R.empty() || R.wasNotFoundInCurrentInstantiation())
+ // The record definition is complete, now look up the member.
+ SemaRef.LookupQualifiedName(R, DC, SS);
+
+ if (!R.empty())
return false;
DeclarationName Typo = R.getLookupName();
SourceLocation TypoLoc = R.getNameLoc();
- // Recompute the lookup context.
- DeclContext *DC = SS.isSet() ? SemaRef.computeDeclContext(SS)
- : SemaRef.computeDeclContext(RTy);
struct QueryState {
Sema &SemaRef;
@@ -766,8 +788,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
<< Typo << DC << DroppedSpecifier
<< SS.getRange());
} else {
- SemaRef.Diag(TypoLoc, diag::err_no_member)
- << Typo << DC << (SS.isSet() ? SS.getRange() : BaseRange);
+ SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << DC << BaseRange;
}
},
[=](Sema &SemaRef, TypoExpr *TE, TypoCorrection TC) mutable {
@@ -793,25 +814,34 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
Decl *ObjCImpDecl, bool HasTemplateArgs,
SourceLocation TemplateKWLoc);
-ExprResult Sema::BuildMemberReferenceExpr(
- Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow,
- CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
- NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
- ActOnMemberAccessExtraArgs *ExtraArgs) {
- LookupResult R(*this, NameInfo, LookupMemberName);
+ExprResult
+Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
+ SourceLocation OpLoc, bool IsArrow,
+ CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
+ NamedDecl *FirstQualifierInScope,
+ const DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *TemplateArgs,
+ const Scope *S,
+ ActOnMemberAccessExtraArgs *ExtraArgs) {
+ if (BaseType->isDependentType() ||
+ (SS.isSet() && isDependentScopeSpecifier(SS)) ||
+ NameInfo.getName().isDependentName())
+ return ActOnDependentMemberExpr(Base, BaseType,
+ IsArrow, OpLoc,
+ SS, TemplateKWLoc, FirstQualifierInScope,
+ NameInfo, TemplateArgs);
- if (SS.isInvalid())
- return ExprError();
+ LookupResult R(*this, NameInfo, LookupMemberName);
// Implicit member accesses.
if (!Base) {
TypoExpr *TE = nullptr;
QualType RecordTy = BaseType;
if (IsArrow) RecordTy = RecordTy->castAs<PointerType>()->getPointeeType();
- if (LookupMemberExprInRecord(*this, R, nullptr, RecordTy, OpLoc, IsArrow,
- SS, TemplateArgs != nullptr, TemplateKWLoc,
- TE))
+ if (LookupMemberExprInRecord(
+ *this, R, nullptr, RecordTy->castAs<RecordType>(), OpLoc, IsArrow,
+ SS, TemplateArgs != nullptr, TemplateKWLoc, TE))
return ExprError();
if (TE)
return TE;
@@ -1003,12 +1033,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
const Scope *S,
bool SuppressQualifierCheck,
ActOnMemberAccessExtraArgs *ExtraArgs) {
- assert(!SS.isInvalid() && "nested-name-specifier cannot be invalid");
- if (R.wasNotFoundInCurrentInstantiation())
- return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
- TemplateKWLoc, FirstQualifierInScope,
- R.getLookupNameInfo(), TemplateArgs);
-
QualType BaseType = BaseExprType;
if (IsArrow) {
assert(BaseType->isPointerType());
@@ -1016,11 +1040,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
}
R.setBaseObjectType(BaseType);
- assert((SS.isEmpty()
- ? !BaseType->isDependentType() || computeDeclContext(BaseType)
- : !isDependentScopeSpecifier(SS) || computeDeclContext(SS)) &&
- "dependent lookup context that isn't the current instantiation?");
-
// C++1z [expr.ref]p2:
// For the first option (dot) the first expression shall be a glvalue [...]
if (!IsArrow && BaseExpr && BaseExpr->isPRValue()) {
@@ -1050,11 +1069,13 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
if (R.empty()) {
// Rederive where we looked up.
- DeclContext *DC =
- (SS.isSet() ? computeDeclContext(SS) : computeDeclContext(BaseType));
+ DeclContext *DC = (SS.isSet()
+ ? computeDeclContext(SS, false)
+ : BaseType->castAs<RecordType>()->getDecl());
+
if (ExtraArgs) {
ExprResult RetryExpr;
- if (!IsArrow && BaseExpr && !BaseExpr->isTypeDependent()) {
+ if (!IsArrow && BaseExpr) {
SFINAETrap Trap(*this, true);
ParsedType ObjectType;
bool MayBePseudoDestructor = false;
@@ -1077,12 +1098,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
}
}
- assert(DC);
Diag(R.getNameLoc(), diag::err_no_member)
- << MemberName << DC
- << (SS.isSet()
- ? SS.getRange()
- : (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()));
+ << MemberName << DC
+ << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
return ExprError();
}
@@ -1312,6 +1330,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
return ExprError();
QualType BaseType = BaseExpr.get()->getType();
+ assert(!BaseType->isDependentType());
DeclarationName MemberName = R.getLookupName();
SourceLocation MemberLoc = R.getNameLoc();
@@ -1323,31 +1342,29 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
if (IsArrow) {
if (const PointerType *Ptr = BaseType->getAs<PointerType>())
BaseType = Ptr->getPointeeType();
- else if (!BaseType->isDependentType()) {
- if (const ObjCObjectPointerType *Ptr =
- BaseType->getAs<ObjCObjectPointerType>())
- BaseType = Ptr->getPointeeType();
- else if (BaseType->isRecordType()) {
- // Recover from arrow accesses to records, e.g.:
- // struct MyRecord foo;
- // foo->bar
- // This is actually well-formed in C++ if MyRecord has an
- // overloaded operator->, but that should have been dealt with
- // by now--or a diagnostic message already issued if a problem
- // was encountered while looking for the overloaded operator->.
- if (!S.getLangOpts().CPlusPlus) {
- S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateReplacement(OpLoc, ".");
- }
- IsArrow = false;
- } else if (BaseType->isFunctionType()) {
- goto fail;
- } else {
- S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
- << BaseType << BaseExpr.get()->getSourceRange();
- return ExprError();
+ else if (const ObjCObjectPointerType *Ptr
+ = BaseType->getAs<ObjCObjectPointerType>())
+ BaseType = Ptr->getPointeeType();
+ else if (BaseType->isRecordType()) {
+ // Recover from arrow accesses to records, e.g.:
+ // struct MyRecord foo;
+ // foo->bar
+ // This is actually well-formed in C++ if MyRecord has an
+ // overloaded operator->, but that should have been dealt with
+ // by now--or a diagnostic message already issued if a problem
+ // was encountered while looking for the overloaded operator->.
+ if (!S.getLangOpts().CPlusPlus) {
+ S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
+ << FixItHint::CreateReplacement(OpLoc, ".");
}
+ IsArrow = false;
+ } else if (BaseType->isFunctionType()) {
+ goto fail;
+ } else {
+ S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
+ << BaseType << BaseExpr.get()->getSourceRange();
+ return ExprError();
}
}
@@ -1367,10 +1384,10 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
}
// Handle field access to simple records.
- if (BaseType->getAsRecordDecl() || BaseType->isDependentType()) {
+ if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
TypoExpr *TE = nullptr;
- if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow,
- SS, HasTemplateArgs, TemplateKWLoc, TE))
+ if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy, OpLoc, IsArrow, SS,
+ HasTemplateArgs, TemplateKWLoc, TE))
return ExprError();
// Returning valid-but-null is how we indicate to the caller that
@@ -1807,6 +1824,13 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
if (Result.isInvalid()) return ExprError();
Base = Result.get();
+ if (Base->getType()->isDependentType() || Name.isDependentName() ||
+ isDependentScopeSpecifier(SS)) {
+ return ActOnDependentMemberExpr(Base, Base->getType(), IsArrow, OpLoc, SS,
+ TemplateKWLoc, FirstQualifierInScope,
+ NameInfo, TemplateArgs);
+ }
+
ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl};
ExprResult Res = BuildMemberReferenceExpr(
Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc,
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index a537eccc2ebaf0..55af414df39f51 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -1282,31 +1282,6 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
if (DeclContext *DC = PreS->getEntity())
DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC);
}
- // C++23 [temp.dep.general]p2:
- // The component name of an unqualified-id is dependent if
- // - it is a conversion-function-id whose conversion-type-id
- // is dependent, or
- // - it is operator= and the current class is a templated entity, or
- // - the unqualified-id is the postfix-expression in a dependent call.
- if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
- Name.getCXXNameType()->isDependentType()) {
- R.setNotFoundInCurrentInstantiation();
- return false;
- }
-
- // If this is the name of an implicitly-declared special member function,
- // go through the scope stack to implicitly declare
- if (isImplicitlyDeclaredMemberFunctionName(Name)) {
- for (Scope *PreS = S; PreS; PreS = PreS->getParent())
- if (DeclContext *DC = PreS->getEntity()) {
- if (DC->isDependentContext() && isa<CXXRecordDecl>(DC) &&
- Name.getCXXOverloadedOperator() == OO_Equal) {
- R.setNotFoundInCurrentInstantiation();
- return false;
- }
- DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC);
- }
- }
// Implicitly declare member functions with the name we're looking for, if in
// fact we are in a scope where it matters.
@@ -2471,33 +2446,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
}
} QL(LookupCtx);
- CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx);
- // FIXME: Per [temp.dep.general]p2, an unqualified name is also dependent
- // if it's a dependent conversion-function-id or operator= where the current
- // class is a templated entity. This should be handled in LookupName.
- if (!InUnqualifiedLookup && !R.isForRedeclaration()) {
- // C++23 [temp.dep.type]p5:
- // A qualified name is dependent if
- // - it is a conversion-function-id whose conversion-type-id
- // is dependent, or
- // - [...]
- // - its lookup context is the current instantiation and it
- // is operator=, or
- // - [...]
- if (DeclarationName Name = R.getLookupName();
- (Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
- Name.getCXXNameType()->isDependentType()) ||
- (Name.getCXXOverloadedOperator() == OO_Equal && LookupRec &&
- LookupRec->isDependentContext())) {
- R.setNotFoundInCurrentInstantiation();
- return false;
- }
- }
-
if (LookupDirect(*this, R, LookupCtx)) {
R.resolveKind();
- if (LookupRec)
- R.setNamingClass(LookupRec);
+ if (isa<CXXRecordDecl>(LookupCtx))
+ R.setNamingClass(cast<CXXRecordDecl>(LookupCtx));
return true;
}
@@ -2519,6 +2471,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// If this isn't a C++ class, we aren't allowed to look into base
// classes, we're done.
+ CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx);
if (!LookupRec || !LookupRec->getDefinition())
return false;
@@ -2765,54 +2718,38 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
///
/// @returns True if any decls were found (but possibly ambiguous)
bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
- QualType ObjectType, bool AllowBuiltinCreation,
- bool EnteringContext) {
- // When the scope specifier is invalid, don't even look for anything.
- if (SS && SS->isInvalid())
+ bool AllowBuiltinCreation, bool EnteringContext) {
+ if (SS && SS->isInvalid()) {
+ // When the scope specifier is invalid, don't even look for
+ // anything.
return false;
+ }
- // Determine where to perform name lookup
- DeclContext *DC = nullptr;
- bool IsDependent = 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 || SS->isEmpty()) &&
- "ObjectType and scope specifier cannot coexist");
- DC = computeDeclContext(ObjectType);
- IsDependent = !DC && ObjectType->isDependentType();
- assert(((!DC && ObjectType->isDependentType()) ||
- !ObjectType->isIncompleteType() || !ObjectType->getAs<TagType>() ||
- ObjectType->castAs<TagType>()->isBeingDefined()) &&
- "Caller should have completed object type");
- } else if (SS && SS->isNotEmpty()) {
- if (NestedNameSpecifier *NNS = SS->getScopeRep();
- NNS->getKind() == NestedNameSpecifier::Super)
+ if (SS && SS->isSet()) {
+ NestedNameSpecifier *NNS = SS->getScopeRep();
+ if (NNS->getKind() == NestedNameSpecifier::Super)
return LookupInSuper(R, NNS->getAsRecordDecl());
- // This nested-name-specifier occurs after another nested-name-specifier,
- // so long into the context associated with the prior nested-name-specifier.
- if (DC = computeDeclContext(*SS, EnteringContext)) {
- // The declaration context must be complete.
+
+ if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) {
+ // We have resolved the scope specifier to a particular declaration
+ // contex, and will perform name lookup in that context.
if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS, DC))
return false;
+
R.setContextRange(SS->getRange());
+ return LookupQualifiedName(R, DC);
}
- IsDependent = !DC && isDependentScopeSpecifier(*SS);
- } else {
- // Perform unqualified name lookup starting in the given scope.
- return LookupName(R, S, AllowBuiltinCreation);
- }
- // If we were able to compute a declaration context, perform qualified name
- // lookup in that context.
- if (DC)
- return LookupQualifiedName(R, DC);
- else if (IsDependent)
// We could not resolve the scope specified to a specific declaration
// context, which means that SS refers to an unknown specialization.
// Name lookup can't find anything in this case.
R.setNotFoundInCurrentInstantiation();
- return false;
+ R.setContextRange(SS->getRange());
+ return false;
+ }
+
+ // Perform unqualified name lookup starting in the given scope.
+ return LookupName(R, S, AllowBuiltinCreation);
}
/// Perform qualified name lookup into all base classes of the given
@@ -5081,9 +5018,8 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
return;
}
- SemaRef.LookupParsedName(Res, S, SS,
- /*ObjectType=*/QualType(),
- /*AllowBuiltinCreation=*/false, EnteringContext);
+ SemaRef.LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false,
+ EnteringContext);
// Fake ivar lookup; this should really be part of
// LookupParsedName.
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index cf5447f223d450..cee8da495c5495 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -3061,9 +3061,7 @@ ExprResult SemaOpenMP::ActOnOpenMPIdExpression(Scope *CurScope,
OpenMPDirectiveKind Kind) {
ASTContext &Context = getASTContext();
LookupResult Lookup(SemaRef, Id, Sema::LookupOrdinaryName);
- SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec,
- /*ObjectType=*/QualType(),
- /*AllowBuiltinCreation=*/true);
+ SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
if (Lookup.isAmbiguous())
return ExprError();
@@ -7409,8 +7407,7 @@ void SemaOpenMP::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(
const IdentifierInfo *BaseII = D.getIdentifier();
LookupResult Lookup(SemaRef, DeclarationName(BaseII), D.getIdentifierLoc(),
Sema::LookupOrdinaryName);
- SemaRef.LookupParsedName(Lookup, S, &D.getCXXScopeSpec(),
- /*ObjectType=*/QualType());
+ SemaRef.LookupParsedName(Lookup, S, &D.getCXXScopeSpec());
TypeSourceInfo *TInfo = SemaRef.GetTypeForDeclarator(D);
QualType FType = TInfo->getType();
@@ -19314,8 +19311,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
if (S) {
LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName);
Lookup.suppressDiagnostics();
- while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec,
- /*ObjectType=*/QualType())) {
+ while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec)) {
NamedDecl *D = Lookup.getRepresentativeDecl();
do {
S = S->getParent();
@@ -22184,8 +22180,7 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName);
Lookup.suppressDiagnostics();
if (S) {
- while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec,
- /*ObjectType=*/QualType())) {
+ while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec)) {
NamedDecl *D = Lookup.getRepresentativeDecl();
while (S && !S->isDeclScope(D))
S = S->getParent();
@@ -23502,9 +23497,7 @@ void SemaOpenMP::DiagnoseUnterminatedOpenMPDeclareTarget() {
NamedDecl *SemaOpenMP::lookupOpenMPDeclareTargetName(
Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id) {
LookupResult Lookup(SemaRef, Id, Sema::LookupOrdinaryName);
- SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec,
- /*ObjectType=*/QualType(),
- /*AllowBuiltinCreation=*/true);
+ SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
if (Lookup.isAmbiguous())
return nullptr;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 72bf6370ca821a..bbcb7c33a98579 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -210,11 +210,10 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
AssumedTemplateKind AssumedTemplate;
LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName);
if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
- /*RequiredTemplate=*/SourceLocation(),
+ MemberOfUnknownSpecialization, SourceLocation(),
&AssumedTemplate,
/*AllowTypoCorrection=*/!Disambiguation))
return TNK_Non_template;
- MemberOfUnknownSpecialization = R.wasNotFoundInCurrentInstantiation();
if (AssumedTemplate != AssumedTemplateKind::None) {
TemplateResult = TemplateTy::make(Context.getAssumedTemplateName(TName));
@@ -321,12 +320,15 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
bool Sema::isDeductionGuideName(Scope *S, const IdentifierInfo &Name,
SourceLocation NameLoc, CXXScopeSpec &SS,
ParsedTemplateTy *Template /*=nullptr*/) {
+ bool MemberOfUnknownSpecialization = false;
+
// We could use redeclaration lookup here, but we don't need to: the
// syntactic form of a deduction guide is enough to identify it even
// if we can't look up the template name at all.
LookupResult R(*this, DeclarationName(&Name), NameLoc, LookupOrdinaryName);
if (LookupTemplateName(R, S, SS, /*ObjectType*/ QualType(),
- /*EnteringContext*/ false))
+ /*EnteringContext*/ false,
+ MemberOfUnknownSpecialization))
return false;
if (R.empty()) return false;
@@ -372,8 +374,11 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
return true;
}
-bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
- QualType ObjectType, bool EnteringContext,
+bool Sema::LookupTemplateName(LookupResult &Found,
+ Scope *S, CXXScopeSpec &SS,
+ QualType ObjectType,
+ bool EnteringContext,
+ bool &MemberOfUnknownSpecialization,
RequiredTemplateKind RequiredTemplate,
AssumedTemplateKind *ATK,
bool AllowTypoCorrection) {
@@ -386,6 +391,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
Found.setTemplateNameLookup(true);
// Determine where to perform name lookup
+ MemberOfUnknownSpecialization = false;
DeclContext *LookupCtx = nullptr;
bool IsDependent = false;
if (!ObjectType.isNull()) {
@@ -542,7 +548,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup);
if (Found.empty()) {
if (IsDependent) {
- Found.setNotFoundInCurrentInstantiation();
+ MemberOfUnknownSpecialization = true;
return false;
}
@@ -5589,9 +5595,11 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
RequireCompleteDeclContext(SS, DC))
return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);
+ bool MemberOfUnknownSpecialization;
LookupResult R(*this, NameInfo, LookupOrdinaryName);
if (LookupTemplateName(R, (Scope *)nullptr, SS, QualType(),
- /*Entering*/ false, TemplateKWLoc))
+ /*Entering*/false, MemberOfUnknownSpecialization,
+ TemplateKWLoc))
return ExprError();
if (R.isAmbiguous())
@@ -5712,13 +5720,14 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S,
DeclarationNameInfo DNI = GetNameFromUnqualifiedId(Name);
LookupResult R(*this, DNI.getName(), Name.getBeginLoc(),
LookupOrdinaryName);
+ bool MOUS;
// Tell LookupTemplateName that we require a template so that it diagnoses
// cases where it finds a non-template.
RequiredTemplateKind RTK = TemplateKWLoc.isValid()
? RequiredTemplateKind(TemplateKWLoc)
: TemplateNameIsRequired;
- if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, RTK,
- /*ATK=*/nullptr, /*AllowTypoCorrection=*/false) &&
+ if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, MOUS,
+ RTK, nullptr, /*AllowTypoCorrection=*/false) &&
!R.isAmbiguous()) {
if (LookupCtx)
Diag(Name.getBeginLoc(), diag::err_no_member)
@@ -5807,7 +5816,7 @@ bool Sema::CheckTemplateTypeArgument(
if (auto *II = NameInfo.getName().getAsIdentifierInfo()) {
LookupResult Result(*this, NameInfo, LookupOrdinaryName);
- LookupParsedName(Result, CurScope, &SS, /*ObjectType=*/QualType());
+ LookupParsedName(Result, CurScope, &SS);
if (Result.getAsSingle<TypeDecl>() ||
Result.getResultKind() ==
@@ -11170,8 +11179,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
: TSK_ExplicitInstantiationDeclaration;
LookupResult Previous(*this, NameInfo, LookupOrdinaryName);
- LookupParsedName(Previous, S, &D.getCXXScopeSpec(),
- /*ObjectType=*/QualType());
+ LookupParsedName(Previous, S, &D.getCXXScopeSpec());
if (!R->isFunctionType()) {
// C++ [temp.explicit]p1:
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 28d3d1b79a7424..f47bc219e6fa32 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13217,26 +13217,6 @@ bool TreeTransform<Derived>::TransformOverloadExprDecls(OverloadExpr *Old,
// Resolve a kind, but don't do any further analysis. If it's
// ambiguous, the callee needs to deal with it.
R.resolveKind();
-
- if (Old->hasTemplateKeyword() && !R.empty()) {
- NamedDecl *FoundDecl = R.getRepresentativeDecl()->getUnderlyingDecl();
- getSema().FilterAcceptableTemplateNames(R,
- /*AllowFunctionTemplates=*/true,
- /*AllowDependent=*/true);
- if (R.empty()) {
- // If a 'template' keyword was used, a lookup that finds only non-template
- // names is an error.
- getSema().Diag(R.getNameLoc(),
- diag::err_template_kw_refers_to_non_template)
- << R.getLookupName() << Old->getQualifierLoc().getSourceRange()
- << Old->hasTemplateKeyword() << Old->getTemplateKeywordLoc();
- getSema().Diag(FoundDecl->getLocation(),
- diag::note_template_kw_refers_to_non_template)
- << R.getLookupName();
- return true;
- }
- }
-
return false;
}
diff --git a/clang/test/AST/HLSL/this-reference-template.hlsl b/clang/test/AST/HLSL/this-reference-template.hlsl
index d427e73044b788..60e057986ebf80 100644
--- a/clang/test/AST/HLSL/this-reference-template.hlsl
+++ b/clang/test/AST/HLSL/this-reference-template.hlsl
@@ -24,7 +24,7 @@ void main() {
// CHECK: -CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <line:8:3, line:10:3> line:8:5 getFirst 'K ()' implicit-inline
// CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} <col:16, line:10:3>
// CHECK-NEXT:-ReturnStmt 0x{{[0-9A-Fa-f]+}} <line:9:4, col:16>
-// CHECK-NEXT:-MemberExpr 0x{{[0-9A-Fa-f]+}} <col:11, col:16> 'K' lvalue .First 0x{{[0-9A-Fa-f]+}}
+// CHECK-NEXT:-CXXDependentScopeMemberExpr 0x{{[0-9A-Fa-f]+}} <col:11, col:16> '<dependent type>' lvalue .First
// CHECK-NEXT:-CXXThisExpr 0x{{[0-9A-Fa-f]+}} <col:11> 'Pair<K, V>' lvalue this
// CHECK-NEXT:-CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <line:12:3, line:14:3> line:12:5 getSecond 'V ()' implicit-inline
// CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} <col:17, line:14:3>
diff --git a/clang/test/CXX/drs/dr2xx.cpp b/clang/test/CXX/drs/dr2xx.cpp
index 2b3131be33057a..5d3e8ce4bea3bc 100644
--- a/clang/test/CXX/drs/dr2xx.cpp
+++ b/clang/test/CXX/drs/dr2xx.cpp
@@ -561,9 +561,9 @@ namespace cwg244 { // cwg244: 11
B_ptr->B_alias::~B();
B_ptr->B_alias::~B_alias();
B_ptr->cwg244::~B();
- // expected-error at -1 {{no member named '~B' in namespace 'cwg244'}}
+ // expected-error at -1 {{qualified member access refers to a member in namespace 'cwg244'}}
B_ptr->cwg244::~B_alias();
- // expected-error at -1 {{no member named '~B' in namespace 'cwg244'}}
+ // expected-error at -1 {{qualified member access refers to a member in namespace 'cwg244'}}
}
template<typename T, typename U>
@@ -836,7 +836,7 @@ namespace cwg258 { // cwg258: 2.8
namespace cwg259 { // cwg259: 4
template<typename T> struct A {};
- template struct A<int>; // #cwg259-A-int
+ template struct A<int>; // #cwg259-A-int
template struct A<int>;
// expected-error at -1 {{duplicate explicit instantiation of 'A<int>'}}
// expected-note@#cwg259-A-int {{previous explicit instantiation is here}}
@@ -997,7 +997,7 @@ namespace cwg275 { // cwg275: no
// expected-error at -1 {{no function template matches function template specialization 'f'}}
}
- template <class T> void g(T) {} // #cwg275-g
+ template <class T> void g(T) {} // #cwg275-g
template <> void N::f(char) {}
template <> void f(int) {}
@@ -1164,7 +1164,7 @@ namespace cwg285 { // cwg285: yes
namespace cwg286 { // cwg286: 2.8
template<class T> struct A {
class C {
- template<class T2> struct B {}; // #cwg286-B
+ template<class T2> struct B {}; // #cwg286-B
};
};
diff --git a/clang/test/CXX/drs/dr3xx.cpp b/clang/test/CXX/drs/dr3xx.cpp
index 94227dc031c6ab..3e9228fe21fb64 100644
--- a/clang/test/CXX/drs/dr3xx.cpp
+++ b/clang/test/CXX/drs/dr3xx.cpp
@@ -34,7 +34,7 @@ namespace cwg301 { // cwg301: 3.5
bool b = (void(*)(S, S))operator- < (void(*)(S, S))operator-;
// cxx98-17-warning at -1 {{ordered comparison of function pointers ('void (*)(S, S)' and 'void (*)(S, S)')}}
// cxx20-23-error at -2 {{expected '>'}}
- // cxx20-23-note at -3 {{to match this '<'}}
+ // cxx20-23-note at -3 {{to match this '<'}}
bool c = (void(*)(S, S))operator+ < (void(*)(S, S))operator-;
// expected-error at -1 {{expected '>'}}
// expected-note at -2 {{to match this '<'}}
@@ -642,7 +642,7 @@ namespace cwg339 { // cwg339: 2.8
char xxx(int);
char (&xxx(float))[2];
- template<class T> A<sizeof(xxx((T)0))> f(T) {} // #cwg339-f
+ template<class T> A<sizeof(xxx((T)0))> f(T) {} // #cwg339-f
void test() {
A<1> a = f(0);
@@ -828,7 +828,7 @@ namespace cwg352 { // cwg352: 2.8
void g(A::E e) {
foo(e, &arg);
// expected-error at -1 {{no matching function for call to 'foo'}}
- // expected-note@#cwg352-foo {{candidate template ignored: couldn't infer template argument 'R'}}
+ // expected-note@#cwg352-foo {{candidate template ignored: couldn't infer template argument 'R'}}
using A::foo;
foo<int, int>(e, &arg); // ok, uses non-template
@@ -929,7 +929,7 @@ namespace cwg352 { // cwg352: 2.8
namespace example5 {
template<int I> class A {};
- template<int I> void g(A<I+1>); // #cwg352-g
+ template<int I> void g(A<I+1>); // #cwg352-g
template<int I> void f(A<I>, A<I+1>);
void h(A<1> a1, A<2> a2) {
g(a1);
@@ -1256,7 +1256,7 @@ namespace cwg373 { // cwg373: 5
}
};
- struct A { struct B {}; }; // #cwg373-A
+ struct A { struct B {}; }; // #cwg373-A
namespace X = A::B;
// expected-error at -1 {{expected namespace name}}
// expected-note@#cwg373-A {{'A' declared here}}
@@ -1608,7 +1608,7 @@ namespace cwg395 { // cwg395: 3.0
// expected-error at -2 {{conversion function cannot have any parameters}}
// expected-error at -3 {{cannot specify any part of a return type in the declaration of a conversion function}}
// expected-error at -4 {{conversion function cannot convert to a function type}}
-
+
};
struct null1_t {
@@ -1721,9 +1721,9 @@ namespace cwg399 { // cwg399: 11
B_ptr->B_alias::~B();
B_ptr->B_alias::~B_alias();
B_ptr->cwg399::~B();
- // expected-error at -1 {{no member named '~B' in namespace 'cwg399'}}
+ // expected-error at -1 {{qualified member access refers to a member in namespace 'cwg399'}}
B_ptr->cwg399::~B_alias();
- // expected-error at -1 {{no member named '~B' in namespace 'cwg399'}}
+ // expected-error at -1 {{qualified member access refers to a member in namespace 'cwg399'}}
}
template<typename T, typename U>
diff --git a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
deleted file mode 100644
index b1d2859be863aa..00000000000000
--- a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
+++ /dev/null
@@ -1,456 +0,0 @@
-// RUN: %clang_cc1 -Wno-unused-value -verify %s
-
-namespace N0 {
- struct A {
- int x0;
- static int y0;
- int x1;
- static int y1;
-
- void f0();
- static void g0();
- void f1();
- static void g1();
-
- using M0 = int;
- using M1 = int;
-
- struct C0 { };
- struct C1 { };
- };
-
- template<typename T>
- struct B : A {
- int x2;
- static int y2;
-
- void f2();
- static void g2();
-
- using M2 = int;
-
- struct C2 { };
-
- using A::x1;
- using A::y1;
- using A::f1;
- using A::g1;
- using A::M1;
- using A::C1;
-
- using T::x3;
- using T::y3;
- using T::f3;
- using T::g3;
- using typename T::M3;
- using typename T::C3;
-
- void not_instantiated(B *a, B &b) {
- // All of the following should be found in the current instantiation.
-
- new M0;
- new B::M0;
- new A::M0;
- new B::A::M0;
- new C0;
- new B::C0;
- new A::C0;
- new B::A::C0;
- new M1;
- new B::M1;
- new A::M1;
- new B::A::M1;
- new C1;
- new B::C1;
- new A::C1;
- new B::A::C1;
- new M2;
- new B::M2;
- new C2;
- new B::C2;
- new M3;
- new B::M3;
- new C3;
- new B::C3;
-
- x0;
- B::x0;
- A::x0;
- B::A::x0;
- y0;
- B::y0;
- A::y0;
- B::A::y0;
- x1;
- B::x1;
- A::x1;
- B::A::x1;
- y1;
- B::y1;
- A::y1;
- B::A::y1;
- x2;
- B::x2;
- y2;
- B::y2;
- x3;
- B::x3;
- y3;
- B::y3;
-
- f0();
- B::f0();
- A::f0();
- B::A::f0();
- g0();
- B::g0();
- A::g0();
- B::A::g0();
- f1();
- B::f1();
- A::f1();
- B::A::f1();
- g1();
- B::g1();
- A::g1();
- B::A::g1();
- f2();
- B::f2();
- g2();
- B::g2();
- f3();
- B::f3();
- g3();
- B::g3();
-
- this->x0;
- this->B::x0;
- this->A::x0;
- this->B::A::x0;
- this->y0;
- this->B::y0;
- this->A::y0;
- this->B::A::y0;
- this->x1;
- this->B::x1;
- this->A::x1;
- this->B::A::x1;
- this->y1;
- this->B::y1;
- this->A::y1;
- this->B::A::y1;
- this->x2;
- this->B::x2;
- this->y2;
- this->B::y2;
- this->x3;
- this->B::x3;
- this->y3;
- this->B::y3;
-
- this->f0();
- this->B::f0();
- this->A::f0();
- this->B::A::f0();
- this->g0();
- this->B::g0();
- this->A::g0();
- this->B::A::g0();
- this->f1();
- this->B::f1();
- this->A::f1();
- this->B::A::f1();
- this->g1();
- this->B::g1();
- this->A::g1();
- this->B::A::g1();
- this->f2();
- this->B::f2();
- this->g2();
- this->B::g2();
- this->f3();
- this->B::f3();
- this->g3();
- this->B::g3();
-
- a->x0;
- a->B::x0;
- a->A::x0;
- a->B::A::x0;
- a->y0;
- a->B::y0;
- a->A::y0;
- a->B::A::y0;
- a->x1;
- a->B::x1;
- a->A::x1;
- a->B::A::x1;
- a->y1;
- a->B::y1;
- a->A::y1;
- a->B::A::y1;
- a->x2;
- a->B::x2;
- a->y2;
- a->B::y2;
- a->x3;
- a->B::x3;
- a->y3;
- a->B::y3;
-
- a->f0();
- a->B::f0();
- a->A::f0();
- a->B::A::f0();
- a->g0();
- a->B::g0();
- a->A::g0();
- a->B::A::g0();
- a->f1();
- a->B::f1();
- a->A::f1();
- a->B::A::f1();
- a->g1();
- a->B::g1();
- a->A::g1();
- a->B::A::g1();
- a->f2();
- a->B::f2();
- a->g2();
- a->B::g2();
- a->f3();
- a->B::f3();
- a->g3();
- a->B::g3();
-
- (*this).x0;
- (*this).B::x0;
- (*this).A::x0;
- (*this).B::A::x0;
- (*this).y0;
- (*this).B::y0;
- (*this).A::y0;
- (*this).B::A::y0;
- (*this).x1;
- (*this).B::x1;
- (*this).A::x1;
- (*this).B::A::x1;
- (*this).y1;
- (*this).B::y1;
- (*this).A::y1;
- (*this).B::A::y1;
- (*this).x2;
- (*this).B::x2;
- (*this).y2;
- (*this).B::y2;
- (*this).x3;
- (*this).B::x3;
- (*this).y3;
- (*this).B::y3;
-
- (*this).f0();
- (*this).B::f0();
- (*this).A::f0();
- (*this).B::A::f0();
- (*this).g0();
- (*this).B::g0();
- (*this).A::g0();
- (*this).B::A::g0();
- (*this).f1();
- (*this).B::f1();
- (*this).A::f1();
- (*this).B::A::f1();
- (*this).g1();
- (*this).B::g1();
- (*this).A::g1();
- (*this).B::A::g1();
- (*this).f2();
- (*this).B::f2();
- (*this).g2();
- (*this).B::g2();
- (*this).f3();
- (*this).B::f3();
- (*this).g3();
- (*this).B::g3();
-
- b.x0;
- b.B::x0;
- b.A::x0;
- b.B::A::x0;
- b.y0;
- b.B::y0;
- b.A::y0;
- b.B::A::y0;
- b.x1;
- b.B::x1;
- b.A::x1;
- b.B::A::x1;
- b.y1;
- b.B::y1;
- b.A::y1;
- b.B::A::y1;
- b.x2;
- b.B::x2;
- b.y2;
- b.B::y2;
- b.x3;
- b.B::x3;
- b.y3;
- b.B::y3;
-
- b.f0();
- b.B::f0();
- b.A::f0();
- b.B::A::f0();
- b.g0();
- b.B::g0();
- b.A::g0();
- b.B::A::g0();
- b.f1();
- b.B::f1();
- b.A::f1();
- b.B::A::f1();
- b.g1();
- b.B::g1();
- b.A::g1();
- b.B::A::g1();
- b.f2();
- b.B::f2();
- b.g2();
- b.B::g2();
- b.f3();
- b.B::f3();
- b.g3();
- b.B::g3();
-
- // None of the following should be found in the current instantiation.
-
- new M4; // expected-error{{unknown type name 'M4'}}
- new B::M4; // expected-error{{no type named 'M4' in 'B<T>'}}
- new A::M4; // expected-error{{no type named 'M4' in 'N0::A'}}
- new B::A::M4; // expected-error{{no type named 'M4' in 'N0::A'}}
-
- x4; // expected-error{{use of undeclared identifier 'x4'}}
- B::x4; // expected-error{{no member named 'x4' in 'B<T>'}}
- A::x4; // expected-error{{no member named 'x4' in 'N0::A'}}
- B::A::x4; // expected-error{{no member named 'x4' in 'N0::A'}}
- f4(); // expected-error{{use of undeclared identifier 'f4'}}
- B::f4(); // expected-error{{no member named 'f4' in 'B<T>'}}
- A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}}
- B::A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}}
-
- this->x4; // expected-error{{no member named 'x4' in 'B<T>'}}
- this->B::x4; // expected-error{{no member named 'x4' in 'B<T>'}}
- this->A::x4; // expected-error{{no member named 'x4' in 'N0::A'}}
- this->B::A::x4; // expected-error{{no member named 'x4' in 'N0::A'}}
- this->f4(); // expected-error{{no member named 'f4' in 'B<T>'}}
- this->B::f4(); // expected-error{{no member named 'f4' in 'B<T>'}}
- this->A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}}
- this->B::A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}}
-
- a->x4; // expected-error{{no member named 'x4' in 'B<T>'}}
- a->B::x4; // expected-error{{no member named 'x4' in 'B<T>'}}
- a->A::x4; // expected-error{{no member named 'x4' in 'N0::A'}}
- a->B::A::x4; // expected-error{{no member named 'x4' in 'N0::A'}}
- a->f4(); // expected-error{{no member named 'f4' in 'B<T>'}}
- a->B::f4(); // expected-error{{no member named 'f4' in 'B<T>'}}
- a->A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}}
- a->B::A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}}
-
- // FIXME: An overloaded unary 'operator*' is built for these
- // even though the operand is a pointer (to a dependent type).
- // Type::isOverloadableType should return false for such cases.
- (*this).x4;
- (*this).B::x4;
- (*this).A::x4;
- (*this).B::A::x4;
- (*this).f4();
- (*this).B::f4();
- (*this).A::f4();
- (*this).B::A::f4();
-
- b.x4; // expected-error{{no member named 'x4' in 'B<T>'}}
- b.B::x4; // expected-error{{no member named 'x4' in 'B<T>'}}
- b.A::x4; // expected-error{{no member named 'x4' in 'N0::A'}}
- b.B::A::x4; // expected-error{{no member named 'x4' in 'N0::A'}}
- b.f4(); // expected-error{{no member named 'f4' in 'B<T>'}}
- b.B::f4(); // expected-error{{no member named 'f4' in 'B<T>'}}
- b.A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}}
- b.B::A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}}
- }
- };
-} // namespace N0
-
-namespace N1 {
- struct A {
- template<int I>
- void f();
- };
-
- template<typename T>
- struct B {
- template<int I>
- void f();
-
- A x;
- A g();
-
- void not_instantiated(B *a, B &b) {
- f<0>();
- this->f<0>();
- a->f<0>();
- // FIXME: This should not require 'template'!
- (*this).f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
- b.f<0>();
-
- x.f<0>();
- this->x.f<0>();
- a->x.f<0>();
- // FIXME: This should not require 'template'!
- (*this).x.f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
- b.x.f<0>();
-
- // FIXME: None of these should require 'template'!
- g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
- this->g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
- a->g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
- (*this).g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
- b.g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
- }
- };
-} // namespace N1
-
-namespace N2 {
- template<typename T>
- struct A {
- struct B {
- using C = A;
-
- void not_instantiated(A *a, B *b) {
- b->x; // expected-error{{no member named 'x' in 'N2::A::B'}}
- b->B::x; // expected-error{{no member named 'x' in 'N2::A::B'}}
- a->B::C::x; // expected-error{{no member named 'x' in 'A<T>'}}
- }
- };
-
- void not_instantiated(A *a, B *b) {
- b->x;
- b->B::x;
- a->B::C::x;
- }
- };
-}
-
-namespace N3 {
- struct A { };
-
- template<typename T>
- struct B : A {
- void not_instantiated() {
- // Dependent, lookup context is the current instantiation.
- this->operator=(*this);
- // Not dependent, the lookup context is A (not the current instantiation).
- this->A::operator=(*this);
- }
- };
-}
diff --git a/clang/test/CXX/temp/temp.res/temp.local/p3.cpp b/clang/test/CXX/temp/temp.res/temp.local/p3.cpp
index b9b29d22736e23..87589e1e5bcdc8 100644
--- a/clang/test/CXX/temp/temp.res/temp.local/p3.cpp
+++ b/clang/test/CXX/temp/temp.res/temp.local/p3.cpp
@@ -16,7 +16,8 @@ template <class T> struct Derived: Base<int>, Base<char> {
void g(X0 *t) {
t->Derived::Base<T>::f();
t->Base<T>::f();
- t->Base::f(); // expected-error{{member 'Base' found in multiple base classes of
diff erent types}}
+ t->Base::f(); // expected-error{{member 'Base' found in multiple base classes of
diff erent types}} \
+ // expected-error{{no member named 'f' in 'X0'}}
}
};
diff --git a/clang/test/CodeGenCXX/mangle.cpp b/clang/test/CodeGenCXX/mangle.cpp
index d0800af55c87e8..31467d943840e0 100644
--- a/clang/test/CodeGenCXX/mangle.cpp
+++ b/clang/test/CodeGenCXX/mangle.cpp
@@ -1032,6 +1032,10 @@ namespace test51 {
template <typename T>
decltype(S1<T>().~S1<T>(), S1<T>().~S1<T>()) fun4() {};
template <typename T>
+ decltype(S1<int>().~S1<T>()) fun5(){};
+ template <template <typename T> class U>
+ decltype(S1<int>().~U<int>()) fun6(){};
+ template <typename T>
decltype(E().E::~T()) fun7() {}
template <template <typename> class U>
decltype(X<int>::Y().U<int>::Y::~Y()) fun8() {}
@@ -1043,6 +1047,10 @@ namespace test51 {
// CHECK-LABEL: @_ZN6test514fun3I2S1IiEiEEDTcldtcvS1_IT0_E_EdnT_EEv
template void fun4<int>();
// CHECK-LABEL: @_ZN6test514fun4IiEEDTcmcldtcv2S1IT_E_Edn2S1IS2_EEcldtcvS3__Edn2S1IS2_EEEv
+ template void fun5<int>();
+ // CHECK-LABEL: @_ZN6test514fun5IiEEDTcldtcv2S1IiE_Edn2S1IT_EEEv
+ template void fun6<S1>();
+ // CHECK-LABEL: @_ZN6test514fun6I2S1EEDTcldtcvS1_IiE_EdnT_IiEEEv
template void fun7<E>();
// CHECK-LABEL: @_ZN6test514fun7INS_1EEEEDTcldtcvS1__Esr1EEdnT_EEv
template void fun8<X>();
diff --git a/clang/test/Index/annotate-nested-name-specifier.cpp b/clang/test/Index/annotate-nested-name-specifier.cpp
index 3181497258407f..a7338db6b05b77 100644
--- a/clang/test/Index/annotate-nested-name-specifier.cpp
+++ b/clang/test/Index/annotate-nested-name-specifier.cpp
@@ -132,7 +132,7 @@ struct X8 {
struct X9 : X8 {
typedef X8 inherited;
- void f() {
+ void f() {
inherited::f();
}
};
@@ -299,7 +299,7 @@ struct X9 : X8 {
// CHECK: Identifier: "type" [77:16 - 77:20] TypeRef=X4::type:70:13
// CHECK: Punctuation: ">" [77:20 - 77:21] MemberRefExpr=
// CHECK: Punctuation: "::" [77:21 - 77:23] MemberRefExpr=
-// CHECK: Identifier: "g" [77:23 - 77:24] OverloadedDeclRef=
+// CHECK: Identifier: "g" [77:23 - 77:24] MemberRefExpr=
// CHECK: Punctuation: "(" [77:24 - 77:25] CallExpr=
// CHECK: Identifier: "t" [77:25 - 77:26] DeclRefExpr=t:74:12
// CHECK: Punctuation: ")" [77:26 - 77:27] CallExpr=
diff --git a/clang/test/SemaCXX/member-expr.cpp b/clang/test/SemaCXX/member-expr.cpp
index 0596e40f6c2f6a..75c9ef0caa2e00 100644
--- a/clang/test/SemaCXX/member-expr.cpp
+++ b/clang/test/SemaCXX/member-expr.cpp
@@ -40,8 +40,8 @@ namespace C {
}
void test2(X *xp) {
- xp->::i = 7; // expected-error{{'i' is not a member of class 'X'}}
- xp->C::i = 7; // expected-error{{'C::i' is not a member of class 'X'}}
+ xp->::i = 7; // expected-error{{qualified member access refers to a member in the global namespace}}
+ xp->C::i = 7; // expected-error{{qualified member access refers to a member in namespace 'C'}}
}
diff --git a/clang/test/SemaTemplate/instantiate-function-1.cpp b/clang/test/SemaTemplate/instantiate-function-1.cpp
index a4967264c654b7..ceef2743774805 100644
--- a/clang/test/SemaTemplate/instantiate-function-1.cpp
+++ b/clang/test/SemaTemplate/instantiate-function-1.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s
template<typename T, typename U>
struct X0 {
- void f(T x, U y) {
+ void f(T x, U y) {
(void)(x + y); // expected-error{{invalid operands}}
}
};
@@ -41,7 +41,7 @@ template <typename T> struct X4 {
T f() const {
return; // expected-error{{non-void function 'f' should return a value}}
}
-
+
T g() const {
return 1; // expected-error{{void function 'g' should not return a value}}
}
@@ -64,7 +64,7 @@ template<typename T, typename U, typename V> struct X6 {
// IfStmt
if (t > 0)
return u;
- else {
+ else {
if (t < 0)
return v; // expected-error{{cannot initialize return object of type}}
}
@@ -131,12 +131,12 @@ template<typename T> struct Member0 {
t;
t.f;
t->f;
-
+
T* tp;
tp.f; // expected-error{{member reference base type 'T *' is not a structure or union}}
tp->f;
- this->f; // expected-error{{reference to non-static member function must be called}}
+ this->f;
this.f; // expected-error{{member reference base type 'Member0<T> *' is not a structure or union}}
}
};
@@ -239,11 +239,11 @@ namespace PR9880 {
static yes_tag check(char[sizeof(&U::luaIndex)]);
enum { value = sizeof(check<T>(0)) == sizeof(yes_tag) };
};
-
+
class SomeClass {
public:
int luaIndex(lua_State* L);
};
-
+
int i = HasIndexMetamethod<SomeClass>::value;
}
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index c08deb903f129b..87774b00956a5a 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -1569,9 +1569,8 @@ TEST_P(ASTMatchersTest, IsArrow_MatchesMemberVariablesViaArrow) {
matches("class Y { void x() { y; } int y; };", memberExpr(isArrow())));
EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } int y; };",
memberExpr(isArrow())));
- EXPECT_TRUE(
- matches("template <class T> class Y { void x() { this->m; } int m; };",
- memberExpr(isArrow())));
+ EXPECT_TRUE(matches("template <class T> class Y { void x() { this->m; } };",
+ cxxDependentScopeMemberExpr(isArrow())));
EXPECT_TRUE(
notMatches("template <class T> class Y { void x() { (*this).m; } };",
cxxDependentScopeMemberExpr(isArrow())));
More information about the cfe-commits
mailing list