summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/DeclBase.cpp9
-rw-r--r--clang/lib/Sema/SemaDecl.cpp66
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp79
-rw-r--r--clang/lib/Sema/SemaLookup.cpp11
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp4
5 files changed, 102 insertions, 67 deletions
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index e99f7ec5b06..e46d671682f 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -1390,14 +1390,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
assert(this == getPrimaryContext() && "expected a primary DC");
// Skip declarations within functions.
- // FIXME: We shouldn't need to build lookup tables for function declarations
- // ever, and we can't do so correctly because we can't model the nesting of
- // scopes which occurs within functions. We use "qualified" lookup into
- // function declarations when handling friend declarations inside nested
- // classes, and consequently accept the following invalid code:
- //
- // void f() { void g(); { int g; struct S { friend void g(); }; } }
- if (isFunctionOrMethod() && !isa<FunctionDecl>(D))
+ if (isFunctionOrMethod())
return;
// Skip declarations which should be invisible to name lookup.
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 15e6a492725..330d0cbb587 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -5033,8 +5033,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// the template out-of-line.
if (!D.getCXXScopeSpec().isInvalid() && !Invalid &&
!PrevVarTemplate) {
- Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)
- << Name << DC << D.getCXXScopeSpec().getRange();
+ Diag(D.getIdentifierLoc(), diag::err_member_decl_does_not_match)
+ << Name << DC << /*IsDefinition*/true
+ << D.getCXXScopeSpec().getRange();
Invalid = true;
}
}
@@ -5914,24 +5915,27 @@ class DifferentNameValidatorCCC : public CorrectionCandidateCallback {
///
/// Returns a NamedDecl iff typo correction was performed and substituting in
/// the new declaration name does not cause new errors.
-static NamedDecl* DiagnoseInvalidRedeclaration(
+static NamedDecl *DiagnoseInvalidRedeclaration(
Sema &SemaRef, LookupResult &Previous, FunctionDecl *NewFD,
- ActOnFDArgs &ExtraArgs) {
+ ActOnFDArgs &ExtraArgs, bool IsLocalFriend, Scope *S) {
NamedDecl *Result = NULL;
DeclarationName Name = NewFD->getDeclName();
DeclContext *NewDC = NewFD->getDeclContext();
- LookupResult Prev(SemaRef, Name, NewFD->getLocation(),
- Sema::LookupOrdinaryName, Sema::ForRedeclaration);
SmallVector<unsigned, 1> MismatchedParams;
SmallVector<std::pair<FunctionDecl *, unsigned>, 1> NearMatches;
TypoCorrection Correction;
- bool isFriendDecl = (SemaRef.getLangOpts().CPlusPlus &&
- ExtraArgs.D.getDeclSpec().isFriendSpecified());
- unsigned DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend
- : diag::err_member_def_does_not_match;
+ unsigned DiagMsg = IsLocalFriend ? diag::err_no_matching_local_friend
+ : diag::err_member_decl_does_not_match;
+ LookupResult Prev(SemaRef, Name, NewFD->getLocation(),
+ IsLocalFriend ? Sema::LookupLocalFriendName
+ : Sema::LookupOrdinaryName,
+ Sema::ForRedeclaration);
NewFD->setInvalidDecl();
- SemaRef.LookupQualifiedName(Prev, NewDC);
+ if (IsLocalFriend)
+ SemaRef.LookupName(Prev, S);
+ else
+ SemaRef.LookupQualifiedName(Prev, NewDC);
assert(!Prev.isAmbiguous() &&
"Cannot have an ambiguity in previous-declaration lookup");
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
@@ -5951,9 +5955,9 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
}
}
// If the qualified name lookup yielded nothing, try typo correction
- } else if ((Correction = SemaRef.CorrectTypo(Prev.getLookupNameInfo(),
- Prev.getLookupKind(), 0, 0,
- Validator, NewDC))) {
+ } else if ((Correction = SemaRef.CorrectTypo(
+ Prev.getLookupNameInfo(), Prev.getLookupKind(), S, 0,
+ Validator, IsLocalFriend ? 0 : NewDC))) {
// Trap errors.
Sema::SFINAETrap Trap(SemaRef);
@@ -6000,11 +6004,12 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
// Ignore the correction if it didn't yield any close FunctionDecl matches
Correction = TypoCorrection();
} else {
- DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend_suggest
- : diag::err_member_def_does_not_match_suggest;
+ DiagMsg = IsLocalFriend ? diag::err_no_matching_local_friend_suggest
+ : diag::err_member_decl_does_not_match_suggest;
}
}
+ bool IsDefinition = ExtraArgs.D.isFunctionDefinition();
if (Correction) {
// FIXME: use Correction.getCorrectionRange() instead of computing the range
// here. This requires passing in the CXXScopeSpec to CorrectTypo which in
@@ -6016,11 +6021,12 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
FixItLoc.setBegin(SS.getBeginLoc());
SemaRef.Diag(NewFD->getLocStart(), DiagMsg)
<< Name << NewDC << Correction.getQuoted(SemaRef.getLangOpts())
+ << IsDefinition
<< FixItHint::CreateReplacement(
FixItLoc, Correction.getAsString(SemaRef.getLangOpts()));
} else {
SemaRef.Diag(NewFD->getLocation(), DiagMsg)
- << Name << NewDC << NewFD->getLocation();
+ << Name << NewDC << IsDefinition << NewFD->getLocation();
}
bool NewFDisConst = false;
@@ -6031,16 +6037,18 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end();
NearMatch != NearMatchEnd; ++NearMatch) {
FunctionDecl *FD = NearMatch->first;
- bool FDisConst = false;
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
- FDisConst = MD->isConst();
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
+ bool FDisConst = MD && MD->isConst();
+ bool IsMember = MD || !IsLocalFriend;
if (unsigned Idx = NearMatch->second) {
ParmVarDecl *FDParam = FD->getParamDecl(Idx-1);
SourceLocation Loc = FDParam->getTypeSpecStartLoc();
if (Loc.isInvalid()) Loc = FD->getLocation();
- SemaRef.Diag(Loc, diag::note_member_def_close_param_match)
- << Idx << FDParam->getType() << NewFD->getParamDecl(Idx-1)->getType();
+ SemaRef.Diag(Loc, IsMember ? diag::note_member_def_close_param_match
+ : diag::note_local_decl_close_param_match)
+ << Idx << FDParam->getType()
+ << NewFD->getParamDecl(Idx - 1)->getType();
} else if (Correction) {
SemaRef.Diag(FD->getLocation(), diag::note_previous_decl)
<< Correction.getQuoted(SemaRef.getLangOpts());
@@ -6048,7 +6056,9 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
SemaRef.Diag(FD->getLocation(), diag::note_member_def_close_const_match)
<< NewFDisConst << FD->getSourceRange().getEnd();
} else
- SemaRef.Diag(FD->getLocation(), diag::note_member_def_close_match);
+ SemaRef.Diag(FD->getLocation(),
+ IsMember ? diag::note_member_def_close_match
+ : diag::note_local_decl_close_match);
}
return Result;
}
@@ -7063,9 +7073,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// matches (e.g., those that differ only in cv-qualifiers and
// whether the parameter types are references).
- if (NamedDecl *Result = DiagnoseInvalidRedeclaration(*this, Previous,
- NewFD,
- ExtraArgs)) {
+ if (NamedDecl *Result = DiagnoseInvalidRedeclaration(
+ *this, Previous, NewFD, ExtraArgs, false, 0)) {
AddToScope = ExtraArgs.AddToScope;
return Result;
}
@@ -7074,9 +7083,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Unqualified local friend declarations are required to resolve
// to something.
} else if (isFriend && cast<CXXRecordDecl>(CurContext)->isLocalClass()) {
- if (NamedDecl *Result = DiagnoseInvalidRedeclaration(*this, Previous,
- NewFD,
- ExtraArgs)) {
+ if (NamedDecl *Result = DiagnoseInvalidRedeclaration(
+ *this, Previous, NewFD, ExtraArgs, true, S)) {
AddToScope = ExtraArgs.AddToScope;
return Result;
}
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 31be93b1719..e67719000cc 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -11274,28 +11274,60 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
ForRedeclaration);
- // FIXME: there are different rules in local classes
+ // There are five cases here.
+ // - There's no scope specifier and we're in a local class. Only look
+ // for functions declared in the immediately-enclosing block scope.
+ // We recover from invalid scope qualifiers as if they just weren't there.
+ FunctionDecl *FunctionContainingLocalClass = 0;
+ if ((SS.isInvalid() || !SS.isSet()) &&
+ (FunctionContainingLocalClass =
+ cast<CXXRecordDecl>(CurContext)->isLocalClass())) {
+ // C++11 [class.friend]p11:
+ // If a friend declaration appears in a local class and the name
+ // specified is an unqualified name, a prior declaration is
+ // looked up without considering scopes that are outside the
+ // innermost enclosing non-class scope. For a friend function
+ // declaration, if there is no prior declaration, the program is
+ // ill-formed.
+
+ // Find the innermost enclosing non-class scope. This is the block
+ // scope containing the local class definition (or for a nested class,
+ // the outer local class).
+ DCScope = S->getFnParent();
+
+ // Look up the function name in the scope.
+ Previous.clear(LookupLocalFriendName);
+ LookupName(Previous, S, /*AllowBuiltinCreation*/false);
+
+ if (!Previous.empty()) {
+ // All possible previous declarations must have the same context:
+ // either they were declared at block scope or they are members of
+ // one of the enclosing local classes.
+ DC = Previous.getRepresentativeDecl()->getDeclContext();
+ } else {
+ // This is ill-formed, but provide the context that we would have
+ // declared the function in, if we were permitted to, for error recovery.
+ DC = FunctionContainingLocalClass;
+ }
+
+ // C++ [class.friend]p6:
+ // A function can be defined in a friend declaration of a class if and
+ // only if the class is a non-local class (9.8), the function name is
+ // unqualified, and the function has namespace scope.
+ if (D.isFunctionDefinition()) {
+ Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class);
+ }
- // There are four cases here.
// - There's no scope specifier, in which case we just go to the
// appropriate scope and look for a function or function template
// there as appropriate.
- // Recover from invalid scope qualifiers as if they just weren't there.
- if (SS.isInvalid() || !SS.isSet()) {
- // C++0x [namespace.memdef]p3:
+ } else if (SS.isInvalid() || !SS.isSet()) {
+ // C++11 [namespace.memdef]p3:
// If the name in a friend declaration is neither qualified nor
// a template-id and the declaration is a function or an
// elaborated-type-specifier, the lookup to determine whether
// the entity has been previously declared shall not consider
// any scopes outside the innermost enclosing namespace.
- // C++0x [class.friend]p11:
- // If a friend declaration appears in a local class and the name
- // specified is an unqualified name, a prior declaration is
- // looked up without considering scopes that are outside the
- // innermost enclosing non-class scope. For a friend function
- // declaration, if there is no prior declaration, the program is
- // ill-formed.
- bool isLocal = cast<CXXRecordDecl>(CurContext)->isLocalClass();
bool isTemplateId = D.getName().getKind() == UnqualifiedId::IK_TemplateId;
// Find the appropriate context according to the above.
@@ -11318,10 +11350,6 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
while (true) {
LookupQualifiedName(Previous, LookupDC);
- // TODO: decide what we think about using declarations.
- if (isLocal)
- break;
-
if (!Previous.empty()) {
DC = LookupDC;
break;
@@ -11336,15 +11364,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
}
DCScope = getScopeForDeclContext(S, DC);
-
- // C++ [class.friend]p6:
- // A function can be defined in a friend declaration of a class if and
- // only if the class is a non-local class (9.8), the function name is
- // unqualified, and the function has namespace scope.
- if (isLocal && D.isFunctionDefinition()) {
- Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class);
- }
-
+
// - There's a non-dependent scope specifier, in which case we
// compute it and do a previous lookup there for a function
// or function template.
@@ -11436,15 +11456,18 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
FakeDCScope.setEntity(DC);
DCScope = &FakeDCScope;
}
-
+
bool AddToScope = true;
NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, TInfo, Previous,
TemplateParams, AddToScope);
if (!ND) return 0;
- assert(ND->getDeclContext() == DC);
assert(ND->getLexicalDeclContext() == CurContext);
+ // If we performed typo correction, we might have added a scope specifier
+ // and changed the decl context.
+ DC = ND->getDeclContext();
+
// Add the function declaration to the appropriate lookup tables,
// adjusting the redeclarations list as necessary. We don't
// want to do this yet if the friending class is dependent.
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 82f404f1f2f..fc8b6b9c09a 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -217,6 +217,7 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
case Sema::LookupObjCImplicitSelfParam:
case Sema::LookupOrdinaryName:
case Sema::LookupRedeclarationWithLinkage:
+ case Sema::LookupLocalFriendName:
IDNS = Decl::IDNS_Ordinary;
if (CPlusPlus) {
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Namespace;
@@ -908,6 +909,15 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
return true;
}
+ if (R.getLookupKind() == LookupLocalFriendName && !S->isClassScope()) {
+ // C++11 [class.friend]p11:
+ // If a friend declaration appears in a local class and the name
+ // specified is an unqualified name, a prior declaration is
+ // looked up without considering scopes that are outside the
+ // innermost enclosing non-class scope.
+ return false;
+ }
+
if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC &&
S->getParent() && !S->getParent()->isTemplateParamScope()) {
// We've just searched the last template parameter scope and
@@ -1594,6 +1604,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
case LookupOrdinaryName:
case LookupMemberName:
case LookupRedeclarationWithLinkage:
+ case LookupLocalFriendName:
BaseCallback = &CXXRecordDecl::FindOrdinaryMember;
break;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 50cca0d94ac..bd2936b6141 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1050,8 +1050,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// template out-of-line.
if (!SS.isInvalid() && !Invalid && !PrevClassTemplate) {
Diag(NameLoc, TUK == TUK_Friend ? diag::err_friend_decl_does_not_match
- : diag::err_member_def_does_not_match)
- << Name << SemanticContext << SS.getRange();
+ : diag::err_member_decl_does_not_match)
+ << Name << SemanticContext << /*IsDefinition*/true << SS.getRange();
Invalid = true;
}
}
OpenPOWER on IntegriCloud