summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/Sema.h3
-rw-r--r--clang/lib/Sema/SemaDecl.cpp20
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp45
-rw-r--r--clang/lib/Sema/SemaLookup.cpp29
4 files changed, 56 insertions, 41 deletions
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index b35fe67de61..ddd6d7b5712 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/lib/Sema/Sema.h
@@ -2036,7 +2036,8 @@ public:
ExprArg AssertMessageExpr);
virtual DeclPtrTy ActOnFriendDecl(Scope *S,
- llvm::PointerUnion<const DeclSpec*,Declarator*> D);
+ llvm::PointerUnion<const DeclSpec*,Declarator*> D,
+ bool IsDefinition);
QualType CheckConstructorDeclarator(Declarator &D, QualType R,
FunctionDecl::StorageClass& SC);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index aac79e9fc70..ab5578b378d 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2353,6 +2353,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+ bool isFriend = D.getDeclSpec().isFriendSpecified();
bool isInline = D.getDeclSpec().isInlineSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
@@ -2382,7 +2383,20 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
bool isVirtualOkay = false;
FunctionDecl *NewFD;
- if (D.getKind() == Declarator::DK_Constructor) {
+ if (isFriend) {
+ // DC is the namespace in which the function is being declared.
+ assert(DC->isFileContext() || PrevDecl);
+
+ // C++ [class.friend]p5
+ // A function can be defined in a friend declaration of a
+ // class . . . . Such a function is implicitly inline.
+ isInline |= IsFunctionDefinition;
+
+ NewFD = FriendFunctionDecl::Create(Context, DC,
+ D.getIdentifierLoc(), Name, R,
+ isInline,
+ D.getDeclSpec().getFriendSpecLoc());
+ } else if (D.getKind() == Declarator::DK_Constructor) {
// This is a C++ constructor declaration.
assert(DC->isRecord() &&
"Constructors can only be declared in a member context");
@@ -2643,7 +2657,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) {
// An out-of-line member function declaration must also be a
// definition (C++ [dcl.meaning]p1).
- if (!IsFunctionDefinition) {
+ if (!IsFunctionDefinition && !isFriend) {
Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
<< D.getCXXScopeSpec().getRange();
NewFD->setInvalidDecl();
@@ -4142,7 +4156,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// If a friend declaration in a non-local class first declares a
// class or function, the friend class or function is a member of
// the innermost enclosing namespace.
- while (!SearchDC->isNamespace() && !SearchDC->isTranslationUnit())
+ while (!SearchDC->isFileContext())
SearchDC = SearchDC->getParent();
// The entity of a decl scope is a DeclContext; see PushDeclContext.
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 20862d4c81f..a0bcfb2b780 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -3305,7 +3305,8 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
}
Sema::DeclPtrTy Sema::ActOnFriendDecl(Scope *S,
- llvm::PointerUnion<const DeclSpec*,Declarator*> DU) {
+ llvm::PointerUnion<const DeclSpec*,Declarator*> DU,
+ bool IsDefinition) {
Declarator *D = DU.dyn_cast<Declarator*>();
const DeclSpec &DS = (D ? D->getDeclSpec() : *DU.get<const DeclSpec*>());
@@ -3483,10 +3484,18 @@ Sema::DeclPtrTy Sema::ActOnFriendDecl(Scope *S,
Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
}
+ bool Redeclaration = (FD != 0);
+
+ // If we found a match, create a friend function declaration with
+ // that function as the previous declaration.
+ if (Redeclaration) {
+ // Create it in the semantic context of the original declaration.
+ DC = FD->getDeclContext();
+
// If we didn't find something matching the type exactly, create
// a declaration. This declaration should only be findable via
// argument-dependent lookup.
- if (!FD) {
+ } else {
assert(DC->isFileContext());
// This implies that it has to be an operator or function.
@@ -3498,23 +3507,25 @@ Sema::DeclPtrTy Sema::ActOnFriendDecl(Scope *S,
D->getKind() == Declarator::DK_Destructor ? 1 : 2);
return DeclPtrTy();
}
-
- bool Redeclaration = false;
- NamedDecl *ND = ActOnFunctionDeclarator(S, *D, DC, T,
- /* PrevDecl = */ NULL,
- MultiTemplateParamsArg(*this),
- /* isFunctionDef */ false,
- Redeclaration);
-
- FD = cast_or_null<FunctionDecl>(ND);
-
- // Note that we're creating a declaration but *not* pushing
- // it onto the scope chains.
-
- // TODO: make accessible via argument-dependent lookup.
}
- // TODO: actually register the function as a friend.
+ NamedDecl *ND = ActOnFunctionDeclarator(S, *D, DC, T,
+ /* PrevDecl = */ FD,
+ MultiTemplateParamsArg(*this),
+ IsDefinition,
+ Redeclaration);
+ FD = cast_or_null<FriendFunctionDecl>(ND);
+
+ // If this is a dependent context, just add the decl to the
+ // class's decl list and don't both with the lookup tables. This
+ // doesn't affect lookup because any call that might find this
+ // function via ADL necessarily has to involve dependently-typed
+ // arguments and hence can't be resolved until
+ // template-instantiation anyway.
+ if (CurContext->isDependentContext())
+ CurContext->addHiddenDecl(FD);
+ else
+ CurContext->addDecl(FD);
return DeclPtrTy::make(FD);
}
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index ef105374fac..c600f99a404 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -1756,28 +1756,17 @@ void Sema::ArgumentDependentLookup(DeclarationName Name,
// associated classes are visible within their respective
// namespaces even if they are not visible during an ordinary
// lookup (11.4).
- //
- // We implement the second clause in the loop below.
- DeclContext::lookup_iterator I, E;
- for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I)
- CollectFunctionDecl(Functions, *I);
- }
-
- // Look for friend function declarations in associated classes
- // which name functions in associated namespaces.
- for (AssociatedClassSet::iterator AC = AssociatedClasses.begin(),
- ACEnd = AssociatedClasses.end();
- AC != ACEnd; ++AC) {
DeclContext::lookup_iterator I, E;
- for (llvm::tie(I, E) = (*AC)->lookup(Name); I != E; ++I) {
+ for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I) {
Decl *D = *I;
- if (!D->isInIdentifierNamespace(Decl::IDNS_Friend))
- continue;
-
- DeclContext *DC = D->getDeclContext();
- if (!AssociatedNamespaces.count(DC))
- continue;
-
+ // Only count friend declarations which were declared in
+ // associated classes.
+ if (D->isInIdentifierNamespace(Decl::IDNS_Friend)) {
+ DeclContext *LexDC = D->getLexicalDeclContext();
+ if (!AssociatedClasses.count(cast<CXXRecordDecl>(LexDC)))
+ continue;
+ }
+
CollectFunctionDecl(Functions, D);
}
}
OpenPOWER on IntegriCloud