[cfe-commits] r80353 - in /cfe/trunk: include/clang/AST/DeclBase.h include/clang/AST/DeclCXX.h include/clang/AST/DeclNodes.def lib/AST/DeclBase.cpp lib/AST/DeclCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaLookup.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CXX/class/class.friend/p1.cpp test/CXX/temp/temp.decls/temp.friend/p1.cpp
John McCall
rjmccall at apple.com
Fri Aug 28 00:59:39 PDT 2009
Author: rjmccall
Date: Fri Aug 28 02:59:38 2009
New Revision: 80353
URL: http://llvm.org/viewvc/llvm-project?rev=80353&view=rev
Log:
Omnibus friend decl refactoring. Instead of cloning AST classes for friend
declarations of same, introduce a single AST class and add appropriate bits
(encoded in the namespace) for whether a decl is "real" or not. Much hackery
about previously-declared / not-previously-declared, but it's essentially
mandated by the standard that friends alter lookup, and this is at least
fairly non-intrusive.
Refactor the Sema methods specific to friends for cleaner flow and less nesting.
Incidentally solve a few bugs, but I remain confident that we can put them back.
Modified:
cfe/trunk/include/clang/AST/DeclBase.h
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/AST/DeclNodes.def
cfe/trunk/lib/AST/DeclBase.cpp
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaLookup.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/test/CXX/class/class.friend/p1.cpp
cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp
Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=80353&r1=80352&r2=80353&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Fri Aug 28 02:59:38 2009
@@ -79,7 +79,9 @@
/// namespaces, labels, tags, members and ordinary
/// identifiers. These are meant as bitmasks, so that searches in
/// C++ can look into the "tag" namespace during ordinary lookup. We
- /// use additional namespaces for Objective-C entities.
+ /// use additional namespaces for Objective-C entities. We also
+ /// put C++ friend declarations (of previously-undeclared entities) in
+ /// shadow namespaces.
enum IdentifierNamespace {
IDNS_Label = 0x1,
IDNS_Tag = 0x2,
@@ -88,7 +90,8 @@
IDNS_ObjCProtocol = 0x10,
IDNS_ObjCImplementation = 0x20,
IDNS_ObjCCategoryImpl = 0x40,
- IDNS_Friend = 0x80
+ IDNS_OrdinaryFriend = 0x80,
+ IDNS_TagFriend = 0x100
};
/// ObjCDeclQualifier - Qualifier used on types in method declarations
@@ -164,7 +167,7 @@
protected:
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
- unsigned IdentifierNamespace : 8;
+ unsigned IdentifierNamespace : 16;
private:
#ifndef NDEBUG
@@ -406,6 +409,42 @@
/// \brief Whether this declaration is a function or function template.
bool isFunctionOrFunctionTemplate() const;
+
+ /// \brief Changes the namespace of this declaration to reflect that it's
+ /// the object of a friend declaration.
+ ///
+ /// These declarations appear in the lexical context of the friending
+ /// class, but in the semantic context of the actual entity. This property
+ /// applies only to a specific decl object; other redeclarations of the
+ /// same entity may not (and probably don't) share this property.
+ void setObjectOfFriendDecl(bool PreviouslyDeclared) {
+ unsigned OldNS = IdentifierNamespace;
+ assert((OldNS == IDNS_Tag || OldNS == IDNS_Ordinary)
+ && "unsupported namespace for undeclared friend");
+ if (!PreviouslyDeclared) IdentifierNamespace = 0;
+
+ if (OldNS == IDNS_Tag)
+ IdentifierNamespace |= IDNS_TagFriend;
+ else
+ IdentifierNamespace |= IDNS_OrdinaryFriend;
+ }
+
+ enum FriendObjectKind {
+ FOK_None, // not a friend object
+ FOK_Declared, // a friend of a previously-declared entity
+ FOK_Undeclared // a friend of a previously-undeclared entity
+ };
+
+ /// \brief Determines whether this declaration is the object of a
+ /// friend declaration and, if so, what kind.
+ ///
+ /// There is currently no direct way to find the associated FriendDecl.
+ FriendObjectKind getFriendObjectKind() const {
+ unsigned mask
+ = (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend));
+ if (!mask) return FOK_None;
+ return (mask & (IDNS_Tag | IDNS_Ordinary) ? FOK_Declared : FOK_Undeclared);
+ }
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *) { return true; }
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=80353&r1=80352&r2=80353&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Fri Aug 28 02:59:38 2009
@@ -1280,83 +1280,68 @@
static bool classof(const CXXConversionDecl *D) { return true; }
};
-/// FriendFunctionDecl - Represents the declaration (and possibly
-/// the definition) of a friend function. For example:
+/// FriendDecl - Represents the declaration of a friend entity,
+/// which can be a function, a type, or a templated function or type.
+// For example:
///
/// @code
-/// class A {
-/// friend int foo(int);
+/// template <typename T> class A {
+/// friend int foo(T);
+/// friend class B;
+/// friend T; // only in C++0x
+/// template <typename U> friend class C;
+/// template <typename U> friend A& operator+=(A&, const U&) { ... }
/// };
/// @endcode
-class FriendFunctionDecl : public FunctionDecl {
- // Location of the 'friend' specifier.
- const SourceLocation FriendLoc;
-
- FriendFunctionDecl(DeclContext *DC, SourceLocation L,
- DeclarationName N, QualType T, DeclaratorInfo *DInfo,
- bool isInline, SourceLocation FriendL)
- : FunctionDecl(FriendFunction, DC, L, N, T, DInfo, None, isInline),
- FriendLoc(FriendL)
- {}
-
+///
+/// The semantic context of a friend decl is its declaring class.
+class FriendDecl : public Decl {
public:
- static FriendFunctionDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, DeclarationName N,
- QualType T, DeclaratorInfo *DInfo,
- bool isInline, SourceLocation FriendL);
+ typedef llvm::PointerUnion<NamedDecl*,Type*> FriendUnion;
- SourceLocation getFriendLoc() const {
- return FriendLoc;
- }
-
- // Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() == FriendFunction;
- }
- static bool classof(const FriendFunctionDecl *D) { return true; }
-};
-
-/// FriendClassDecl - Represents the declaration of a friend class.
-/// For example:
-///
-/// @code
-/// class X {
-/// friend class Y;
-/// };
-/// @endcode
-class FriendClassDecl : public Decl {
- // The friended type. In C++0x, this can be an arbitrary type,
- // which we simply ignore if it's not a record type.
- QualType FriendType;
+private:
+ // The declaration that's a friend of this class.
+ FriendUnion Friend;
// Location of the 'friend' specifier.
SourceLocation FriendLoc;
- FriendClassDecl(DeclContext *DC, SourceLocation L,
- QualType T, SourceLocation FriendL)
- : Decl(FriendClass, DC, L),
- FriendType(T),
+ FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend,
+ SourceLocation FriendL)
+ : Decl(Decl::Friend, DC, L),
+ Friend(Friend),
FriendLoc(FriendL)
{}
public:
- static FriendClassDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, QualType T,
- SourceLocation FriendL);
+ static FriendDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, FriendUnion Friend_,
+ SourceLocation FriendL);
+
+ /// If this friend declaration names an (untemplated but
+ /// possibly dependent) type, return the type; otherwise
+ /// return null. This is used only for C++0x's unelaborated
+ /// friend type declarations.
+ Type *getFriendType() const {
+ return Friend.dyn_cast<Type*>();
+ }
- QualType getFriendType() const {
- return FriendType;
+ /// If this friend declaration doesn't name an unelaborated
+ /// type, return the inner declaration.
+ NamedDecl *getFriendDecl() const {
+ return Friend.dyn_cast<NamedDecl*>();
}
+ /// Retrieves the location of the 'friend' keyword.
SourceLocation getFriendLoc() const {
return FriendLoc;
}
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
- return D->getKind() == FriendClass;
+ return D->getKind() == Decl::Friend;
}
- static bool classof(const FriendClassDecl *D) { return true; }
+ static bool classof(const FriendDecl *D) { return true; }
};
/// LinkageSpecDecl - This represents a linkage specification. For example:
Modified: cfe/trunk/include/clang/AST/DeclNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclNodes.def?rev=80353&r1=80352&r2=80353&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclNodes.def (original)
+++ cfe/trunk/include/clang/AST/DeclNodes.def Fri Aug 28 02:59:38 2009
@@ -93,7 +93,6 @@
DECL(EnumConstant, ValueDecl)
ABSTRACT_DECL(Declarator, NamedDecl)
DECL(Function, ValueDecl)
- DECL(FriendFunction, FunctionDecl)
DECL(CXXMethod, FunctionDecl)
DECL(CXXConstructor, CXXMethodDecl)
DECL(CXXDestructor, CXXMethodDecl)
@@ -127,7 +126,7 @@
DECL(ObjCForwardProtocol, Decl)
DECL(ObjCClass, Decl)
DECL(FileScopeAsm, Decl)
-DECL(FriendClass, Decl)
+DECL(Friend, Decl)
DECL(StaticAssert, Decl)
LAST_DECL(Block, Decl)
Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=80353&r1=80352&r2=80353&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Fri Aug 28 02:59:38 2009
@@ -200,10 +200,6 @@
case ObjCCompatibleAlias:
return IDNS_Ordinary;
- case FriendClass:
- case FriendFunction:
- return IDNS_Friend;
-
case ObjCProtocol:
return IDNS_ObjCProtocol;
@@ -233,6 +229,7 @@
return IDNS_Tag | IDNS_Ordinary;
// Never have names.
+ case Friend:
case LinkageSpec:
case FileScopeAsm:
case StaticAssert:
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=80353&r1=80352&r2=80353&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Fri Aug 28 02:59:38 2009
@@ -777,20 +777,20 @@
return !isa<OverloadedFunctionDecl>(D) || Iter == Other.Iter;
}
-FriendFunctionDecl *FriendFunctionDecl::Create(ASTContext &C,
- DeclContext *DC,
- SourceLocation L,
- DeclarationName N, QualType T,
- DeclaratorInfo *DInfo,
- bool isInline,
- SourceLocation FriendL) {
- return new (C) FriendFunctionDecl(DC, L, N, T, DInfo, isInline, FriendL);
-}
+FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ FriendUnion Friend,
+ SourceLocation FriendL) {
+ if (Friend.is<NamedDecl*>()) {
+ NamedDecl *D = Friend.get<NamedDecl*>();
+ assert(isa<FunctionDecl>(D) ||
+ isa<CXXRecordDecl>(D) ||
+ isa<FunctionTemplateDecl>(D) ||
+ isa<ClassTemplateDecl>(D));
+ assert(D->getFriendObjectKind());
+ }
-FriendClassDecl *FriendClassDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, QualType T,
- SourceLocation FriendL) {
- return new (C) FriendClassDecl(DC, L, T, FriendL);
+ return new (C) FriendDecl(DC, L, Friend, FriendL);
}
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=80353&r1=80352&r2=80353&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Aug 28 02:59:38 2009
@@ -2143,6 +2143,9 @@
virtual DeclPtrTy ActOnFriendDecl(Scope *S,
llvm::PointerUnion<const DeclSpec*,Declarator*> D,
bool IsDefinition);
+ DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec& DS,
+ bool IsDefinition);
+ DeclPtrTy ActOnFriendFunctionDecl(Scope *S, Declarator& D, bool IsDefinition);
QualType CheckConstructorDeclarator(Declarator &D, QualType R,
FunctionDecl::StorageClass& SC);
@@ -2955,6 +2958,7 @@
bool Recursive = false);
NamedDecl *FindInstantiatedDecl(NamedDecl *D);
+ DeclContext *FindInstantiatedContext(DeclContext *DC);
// Objective-C declarations.
virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=80353&r1=80352&r2=80353&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Aug 28 02:59:38 2009
@@ -735,7 +735,7 @@
const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
- if (OldMethod && NewMethod &&
+ if (OldMethod && NewMethod && !NewMethod->getFriendObjectKind() &&
NewMethod->getLexicalDeclContext()->isRecord()) {
// -- Member function declarations with the same name and the
// same parameter types cannot be overloaded if any of them
@@ -2411,6 +2411,7 @@
bool isVirtualOkay = false;
FunctionDecl *NewFD;
+
if (isFriend) {
// DC is the namespace in which the function is being declared.
assert((DC->isFileContext() || PrevDecl) && "previously-undeclared "
@@ -2420,13 +2421,9 @@
// 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, DInfo,
- isInline,
- D.getDeclSpec().getFriendSpecLoc());
-
- } else if (D.getKind() == Declarator::DK_Constructor) {
+ if (D.getKind() == Declarator::DK_Constructor) {
// This is a C++ constructor declaration.
assert(DC->isRecord() &&
"Constructors can only be declared in a member context");
@@ -2514,10 +2511,13 @@
NewFD->setInvalidDecl();
// Set the lexical context. If the declarator has a C++
- // scope specifier, the lexical context will be different
- // from the semantic context.
+ // scope specifier, or is the object of a friend declaration, the
+ // lexical context will be different from the semantic context.
NewFD->setLexicalDeclContext(CurContext);
+ if (isFriend)
+ NewFD->setObjectOfFriendDecl(/* PreviouslyDeclared= */ PrevDecl != NULL);
+
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
FunctionTemplateDecl *FunctionTemplate = 0;
@@ -4310,6 +4310,10 @@
// lexical context will be different from the semantic context.
New->setLexicalDeclContext(CurContext);
+ // Mark this as a friend decl if applicable.
+ if (TUK == TUK_Friend)
+ New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ PrevDecl != NULL);
+
// Set the access specifier.
if (!Invalid && TUK != TUK_Friend)
SetMemberAccessSpecifier(New, PrevDecl, AS);
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=80353&r1=80352&r2=80353&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Aug 28 02:59:38 2009
@@ -3567,116 +3567,124 @@
Sema::DeclPtrTy Sema::ActOnFriendDecl(Scope *S,
llvm::PointerUnion<const DeclSpec*,Declarator*> DU,
bool IsDefinition) {
- Declarator *D = DU.dyn_cast<Declarator*>();
- const DeclSpec &DS = (D ? D->getDeclSpec() : *DU.get<const DeclSpec*>());
+ if (DU.is<Declarator*>())
+ return ActOnFriendFunctionDecl(S, *DU.get<Declarator*>(), IsDefinition);
+ else
+ return ActOnFriendTypeDecl(S, *DU.get<const DeclSpec*>(), IsDefinition);
+}
+
+Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S,
+ const DeclSpec &DS,
+ bool IsDefinition) {
+ SourceLocation Loc = DS.getSourceRange().getBegin();
assert(DS.isFriendSpecified());
assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
- // If there's no declarator, then this can only be a friend class
- // declaration (or else it's just syntactically invalid).
- if (!D) {
- SourceLocation Loc = DS.getSourceRange().getBegin();
-
- QualType T;
- DeclContext *DC;
-
- // In C++0x, we just accept any old type.
- if (getLangOptions().CPlusPlus0x) {
- bool invalid = false;
- QualType T = ConvertDeclSpecToType(DS, Loc, invalid);
- if (invalid)
- return DeclPtrTy();
+ // Check to see if the decl spec was syntactically like "struct foo".
+ RecordDecl *RD = NULL;
- // The semantic context in which to create the decl. If it's not
- // a record decl (or we don't yet know if it is), create it in the
- // current context.
- DC = CurContext;
- if (const RecordType *RT = T->getAs<RecordType>())
- DC = RT->getDecl()->getDeclContext();
-
- // The C++98 rules are somewhat more complex.
- } else {
- // C++ [class.friend]p2:
- // An elaborated-type-specifier shall be used in a friend declaration
- // for a class.*
- // * The class-key of the elaborated-type-specifier is required.
- CXXRecordDecl *RD = 0;
+ switch (DS.getTypeSpecType()) {
+ case DeclSpec::TST_class:
+ case DeclSpec::TST_struct:
+ case DeclSpec::TST_union:
+ RD = dyn_cast_or_null<CXXRecordDecl>((Decl*) DS.getTypeRep());
+ if (!RD) return DeclPtrTy();
+
+ // The parser doesn't quite handle
+ // friend class A {}
+ // as we'd like, because it might have been the (valid) prefix of
+ // friend class A {} foo();
+ // So even in C++0x mode we don't want to
+ IsDefinition |= RD->isDefinition();
+ break;
+
+ default: break;
+ }
+
+ FriendDecl::FriendUnion FU = RD;
+
+ // C++ [class.friend]p2:
+ // An elaborated-type-specifier shall be used in a friend declaration
+ // for a class.*
+ // * The class-key of the elaborated-type-specifier is required.
+ // So if we didn't get a record decl above, we're invalid in C++98 mode.
+ if (!RD) {
+ bool invalid = false;
+ QualType T = ConvertDeclSpecToType(DS, Loc, invalid);
+ if (invalid) return DeclPtrTy();
- switch (DS.getTypeSpecType()) {
- case DeclSpec::TST_class:
- case DeclSpec::TST_struct:
- case DeclSpec::TST_union:
- RD = dyn_cast_or_null<CXXRecordDecl>((Decl*) DS.getTypeRep());
- if (!RD) return DeclPtrTy();
- break;
-
- case DeclSpec::TST_typename:
- if (const RecordType *RT =
- ((const Type*) DS.getTypeRep())->getAs<RecordType>())
- RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
- // fallthrough
- default:
- if (RD) {
- Diag(DS.getFriendSpecLoc(), diag::err_unelaborated_friend_type)
- << (RD->isUnion())
- << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
- RD->isUnion() ? " union" : " class");
- return DeclPtrTy::make(RD);
- }
-
- Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
- << DS.getSourceRange();
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ FU = RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ // Untagged typenames are invalid prior to C++0x, but we can
+ // suggest an easy fix which should work.
+ if (!getLangOptions().CPlusPlus0x) {
+ Diag(DS.getFriendSpecLoc(), diag::err_unelaborated_friend_type)
+ << (RD->isUnion())
+ << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
+ RD->isUnion() ? " union" : " class");
return DeclPtrTy();
}
-
- // The record declaration we get from friend declarations is not
- // canonicalized; see ActOnTag.
-
- // C++ [class.friend]p2: A class shall not be defined inside
- // a friend declaration.
- if (RD->isDefinition())
- Diag(DS.getFriendSpecLoc(), diag::err_friend_decl_defines_class)
- << RD->getSourceRange();
-
- // C++98 [class.friend]p1: A friend of a class is a function
- // or class that is not a member of the class . . .
- // But that's a silly restriction which nobody implements for
- // inner classes, and C++0x removes it anyway, so we only report
- // this (as a warning) if we're being pedantic.
- //
- // Also, definitions currently get treated in a way that causes
- // this error, so only report it if we didn't see a definition.
- else if (RD->getDeclContext() == CurContext &&
- !getLangOptions().CPlusPlus0x)
- Diag(DS.getFriendSpecLoc(), diag::ext_friend_inner_class);
-
- T = QualType(RD->getTypeForDecl(), 0);
- DC = RD->getDeclContext();
+ }else if (!getLangOptions().CPlusPlus0x) {
+ Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
+ << DS.getSourceRange();
+ return DeclPtrTy();
+ }else {
+ FU = T.getTypePtr();
}
+ }
- FriendClassDecl *FCD = FriendClassDecl::Create(Context, DC, Loc, T,
- DS.getFriendSpecLoc());
- FCD->setLexicalDeclContext(CurContext);
+ assert(FU && "should have a friend decl/type by here!");
- if (CurContext->isDependentContext())
- CurContext->addHiddenDecl(FCD);
- else
- CurContext->addDecl(FCD);
+ // C++ [class.friend]p2: A class shall not be defined inside
+ // a friend declaration.
+ if (IsDefinition) {
+ Diag(DS.getFriendSpecLoc(), diag::err_friend_decl_defines_class)
+ << DS.getSourceRange();
+ return DeclPtrTy();
+ }
- return DeclPtrTy::make(FCD);
+ // C++98 [class.friend]p1: A friend of a class is a function
+ // or class that is not a member of the class . . .
+ // But that's a silly restriction which nobody implements for
+ // inner classes, and C++0x removes it anyway, so we only report
+ // this (as a warning) if we're being pedantic.
+ if (!getLangOptions().CPlusPlus0x) {
+ assert(RD && "must have a record decl in C++98 mode");
+ if (RD->getDeclContext() == CurContext)
+ Diag(DS.getFriendSpecLoc(), diag::ext_friend_inner_class);
}
- // We have a declarator.
- assert(D);
+ FriendDecl *FD = FriendDecl::Create(Context, CurContext, Loc, FU,
+ DS.getFriendSpecLoc());
+ CurContext->addDecl(FD);
+
+ return DeclPtrTy::make(FD);
+}
+
+Sema::DeclPtrTy Sema::ActOnFriendFunctionDecl(Scope *S,
+ Declarator &D,
+ bool IsDefinition) {
+ const DeclSpec &DS = D.getDeclSpec();
+
+ assert(DS.isFriendSpecified());
+ assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
- SourceLocation Loc = D->getIdentifierLoc();
+ SourceLocation Loc = D.getIdentifierLoc();
DeclaratorInfo *DInfo = 0;
- QualType T = GetTypeForDeclarator(*D, S, &DInfo);
+ QualType T = GetTypeForDeclarator(D, S, &DInfo);
// C++ [class.friend]p1
// A friend of a class is a function or class....
// Note that this sees through typedefs, which is intended.
+ // It *doesn't* see through dependent types, which is correct
+ // according to [temp.arg.type]p3:
+ // If a declaration acquires a function type through a
+ // type dependent on a template-parameter and this causes
+ // a declaration that does not use the syntactic form of a
+ // function declarator to have a function type, the program
+ // is ill-formed.
if (!T->isFunctionType()) {
Diag(Loc, diag::err_unexpected_friend);
@@ -3700,8 +3708,8 @@
// declared as a friend, scopes outside the innermost enclosing
// namespace scope are not considered.
- CXXScopeSpec &ScopeQual = D->getCXXScopeSpec();
- DeclarationName Name = GetNameForDeclarator(*D);
+ CXXScopeSpec &ScopeQual = D.getCXXScopeSpec();
+ DeclarationName Name = GetNameForDeclarator(D);
assert(Name);
// The existing declaration we found.
@@ -3727,7 +3735,7 @@
// TODO: better diagnostics for this case. Suggesting the right
// qualified scope would be nice...
if (!Dec || Dec->getDeclContext() != DC) {
- D->setInvalidType();
+ D.setInvalidType();
Diag(Loc, diag::err_qualified_friend_not_found) << Name << T;
return DeclPtrTy();
}
@@ -3789,36 +3797,36 @@
assert(DC->isFileContext());
// This implies that it has to be an operator or function.
- if (D->getKind() == Declarator::DK_Constructor ||
- D->getKind() == Declarator::DK_Destructor ||
- D->getKind() == Declarator::DK_Conversion) {
+ if (D.getKind() == Declarator::DK_Constructor ||
+ D.getKind() == Declarator::DK_Destructor ||
+ D.getKind() == Declarator::DK_Conversion) {
Diag(Loc, diag::err_introducing_special_friend) <<
- (D->getKind() == Declarator::DK_Constructor ? 0 :
- D->getKind() == Declarator::DK_Destructor ? 1 : 2);
+ (D.getKind() == Declarator::DK_Constructor ? 0 :
+ D.getKind() == Declarator::DK_Destructor ? 1 : 2);
return DeclPtrTy();
}
}
- NamedDecl *ND = ActOnFunctionDeclarator(S, *D, DC, T, DInfo,
+ NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, DInfo,
/* PrevDecl = */ FD,
MultiTemplateParamsArg(*this),
IsDefinition,
Redeclaration);
- FD = cast_or_null<FriendFunctionDecl>(ND);
+ if (!ND) return DeclPtrTy();
+ FD = cast<FunctionDecl>(ND);
assert(FD->getDeclContext() == DC);
assert(FD->getLexicalDeclContext() == CurContext);
- // 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);
+ // We only add the function declaration to the lookup tables, not
+ // the decl list, and only if the context isn't dependent.
+ if (!CurContext->isDependentContext())
+ DC->makeDeclVisibleInContext(FD);
+
+ FriendDecl *FrD = FriendDecl::Create(Context, CurContext,
+ D.getIdentifierLoc(), FD,
+ DS.getFriendSpecLoc());
+ CurContext->addDecl(FrD);
return DeclPtrTy::make(FD);
}
Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=80353&r1=80352&r2=80353&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Fri Aug 28 02:59:38 2009
@@ -643,6 +643,13 @@
"Can perform only C++ lookup");
unsigned IDNS
= getIdentifierNamespacesFromLookupNameKind(NameKind, /*CPlusPlus*/ true);
+
+ // If we're testing for redeclarations, also look in the friend namespaces.
+ if (RedeclarationOnly) {
+ if (IDNS & Decl::IDNS_Tag) IDNS |= Decl::IDNS_TagFriend;
+ if (IDNS & Decl::IDNS_Ordinary) IDNS |= Decl::IDNS_OrdinaryFriend;
+ }
+
Scope *Initial = S;
DeclContext *OutOfLineCtx = 0;
IdentifierResolver::iterator
@@ -1769,9 +1776,9 @@
DeclContext::lookup_iterator I, E;
for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I) {
Decl *D = *I;
- // Only count friend declarations which were declared in
- // associated classes.
- if (D->isInIdentifierNamespace(Decl::IDNS_Friend)) {
+ // If the only declaration here is an ordinary friend, consider
+ // it only if it was declared in an associated classes.
+ if (D->getIdentifierNamespace() == Decl::IDNS_OrdinaryFriend) {
DeclContext *LexDC = D->getLexicalDeclContext();
if (!AssociatedClasses.count(cast<CXXRecordDecl>(LexDC)))
continue;
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=80353&r1=80352&r2=80353&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Aug 28 02:59:38 2009
@@ -45,7 +45,7 @@
Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
Decl *VisitEnumDecl(EnumDecl *D);
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
- Decl *VisitFriendClassDecl(FriendClassDecl *D);
+ Decl *VisitFriendDecl(FriendDecl *D);
Decl *VisitFunctionDecl(FunctionDecl *D);
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
@@ -250,25 +250,35 @@
return Field;
}
-Decl *TemplateDeclInstantiator::VisitFriendClassDecl(FriendClassDecl *D) {
- QualType T = D->getFriendType();
- if (T->isDependentType()) {
- T = SemaRef.SubstType(T, TemplateArgs, D->getLocation(),
- DeclarationName());
- assert(T.isNull() || getLangOptions().CPlusPlus0x || T->isRecordType());
- }
-
- // FIXME: the target context might be dependent.
- DeclContext *DC = D->getDeclContext();
- assert(DC->isFileContext());
-
- FriendClassDecl *NewD =
- FriendClassDecl::Create(SemaRef.Context, DC, D->getLocation(), T,
- D->getFriendLoc());
- NewD->setLexicalDeclContext(Owner);
+Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
+ FriendDecl::FriendUnion FU;
+
+ // Handle friend type expressions by simply substituting template
+ // parameters into the pattern type.
+ if (Type *Ty = D->getFriendType()) {
+ QualType T = SemaRef.SubstType(QualType(Ty,0), TemplateArgs,
+ D->getLocation(), DeclarationName());
+ if (T.isNull()) return 0;
+
+ assert(getLangOptions().CPlusPlus0x || T->isRecordType());
+ FU = T.getTypePtr();
+
+ // Handle everything else by appropriate substitution.
+ } else {
+ NamedDecl *ND = D->getFriendDecl();
+ assert(ND && "friend decl must be a decl or a type!");
+
+ Decl *NewND = Visit(ND);
+ if (!NewND) return 0;
- Owner->addDecl(NewD);
- return NewD;
+ FU = cast<NamedDecl>(NewND);
+ }
+
+ FriendDecl *FD =
+ FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), FU,
+ D->getFriendLoc());
+ Owner->addDecl(FD);
+ return FD;
}
Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
@@ -424,10 +434,20 @@
if (!D->isInjectedClassName())
Record->setInstantiationOfMemberClass(D);
+ // If the original function was part of a friend declaration,
+ // inherit its namespace state.
+ if (Decl::FriendObjectKind FOK = D->getFriendObjectKind())
+ Record->setObjectOfFriendDecl(FOK == Decl::FOK_Declared);
+
Owner->addDecl(Record);
return Record;
}
+/// Normal class members are of more specific types and therefore
+/// don't make it here. This function serves two purposes:
+/// 1) instantiating function templates
+/// 2) substituting friend declarations
+/// FIXME: preserve function definitions in case #2
Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
// Check whether there is already a function template specialization for
// this declaration.
@@ -457,33 +477,27 @@
return 0;
// Build the instantiated method declaration.
- FunctionDecl *Function;
- if (FriendFunctionDecl* FFD = dyn_cast<FriendFunctionDecl>(D)) {
- // The new decl's semantic context. FIXME: this might need
- // to be instantiated.
- DeclContext *DC = D->getDeclContext();
-
- // This assert is bogus and exists only to catch cases we don't
- // handle yet.
- assert(!DC->isDependentContext());
-
- Function =
- FriendFunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
- D->getDeclName(), T, D->getDeclaratorInfo(),
- D->isInline(), FFD->getFriendLoc());
- Function->setLexicalDeclContext(Owner);
- } else {
- Function =
- FunctionDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ DeclContext *DC = SemaRef.FindInstantiatedContext(D->getDeclContext());
+ FunctionDecl *Function =
+ FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
D->getDeclName(), T, D->getDeclaratorInfo(),
D->getStorageClass(),
D->isInline(), D->hasWrittenPrototype());
- }
-
+ Function->setLexicalDeclContext(Owner);
+
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
Params[P]->setOwningFunction(Function);
Function->setParams(SemaRef.Context, Params.data(), Params.size());
+
+ // If the original function was part of a friend declaration,
+ // inherit its namespace state and add it to the owner.
+ if (Decl::FriendObjectKind FOK = D->getFriendObjectKind()) {
+ bool WasDeclared = (FOK == Decl::FOK_Declared);
+ Function->setObjectOfFriendDecl(WasDeclared);
+ if (!Owner->isDependentContext())
+ DC->makeDeclVisibleInContext(Function);
+ }
if (InitFunctionInstantiation(Function, D))
Function->setInvalidDecl();
@@ -502,17 +516,6 @@
InsertPos);
}
- // If this was a friend function decl, it's a member which
- // needs to be added.
- if (isa<FriendFunctionDecl>(Function)) {
- // If the new context is still dependent, this declaration
- // needs to remain hidden.
- if (Owner->isDependentContext())
- Owner->addHiddenDecl(Function);
- else
- Owner->addDecl(Function);
- }
-
return Function;
}
@@ -1127,6 +1130,17 @@
return 0;
}
+/// \brief Finds the instantiation of the given declaration context
+/// within the current instantiation.
+///
+/// \returns NULL if there was an error
+DeclContext *Sema::FindInstantiatedContext(DeclContext* DC) {
+ if (NamedDecl *D = dyn_cast<NamedDecl>(DC)) {
+ Decl* ID = FindInstantiatedDecl(D);
+ return cast_or_null<DeclContext>(ID);
+ } else return DC;
+}
+
/// \brief Find the instantiation of the given declaration within the
/// current instantiation.
///
@@ -1161,13 +1175,8 @@
return cast<NamedDecl>(CurrentInstantiationScope->getInstantiationOf(D));
}
- if (NamedDecl *ParentDecl = dyn_cast<NamedDecl>(ParentDC)) {
- ParentDecl = FindInstantiatedDecl(ParentDecl);
- if (!ParentDecl)
- return 0;
-
- ParentDC = cast<DeclContext>(ParentDecl);
- }
+ ParentDC = FindInstantiatedContext(ParentDC);
+ if (!ParentDC) return 0;
if (ParentDC != D->getDeclContext()) {
// We performed some kind of instantiation in the parent context,
Modified: cfe/trunk/test/CXX/class/class.friend/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.friend/p1.cpp?rev=80353&r1=80352&r2=80353&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class/class.friend/p1.cpp (original)
+++ cfe/trunk/test/CXX/class/class.friend/p1.cpp Fri Aug 28 02:59:38 2009
@@ -37,6 +37,9 @@
friend void global_function();
friend void global_c_function();
+ friend class UndeclaredSoFar;
+ UndeclaredSoFar x; // expected-error {{ unknown type name 'UndeclaredSoFar' }}
+
void a_member();
friend void A::a_member(); // expected-error {{ friends cannot be members of the declaring class }}
friend void a_member(); // okay (because we ignore class scopes when looking up friends)
@@ -60,6 +63,10 @@
friend ftypedef typedeffed_function; // okay (because it's not declared as a member)
};
+class UndeclaredSoFar { };
+
+A::UndeclaredSoFar y; // expected-error {{ unknown type name 'UndeclaredSoFar' }}
+
class PreDeclared;
int myoperation(float f) {
Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp?rev=80353&r1=80352&r2=80353&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp Fri Aug 28 02:59:38 2009
@@ -1,20 +1,44 @@
// RUN: clang-cc -fsyntax-only -verify %s
-template <typename T> class Num {
+template <typename T> struct Num {
T value_;
public:
Num(T value) : value_(value) {}
T get() const { return value_; }
-
+
+ template <typename U> struct Rep {
+ U count_;
+ Rep(U count) : count_(count) {}
+
+ friend Num operator*(const Num &a, const Rep &n) {
+ Num x = 0;
+ for (U count = n.count_; count; --count)
+ x += a;
+ return x;
+ }
+ };
+
friend Num operator+(const Num &a, const Num &b) {
return a.value_ + b.value_;
}
+
+ Num& operator+=(const Num& b) {
+ value_ += b.value_;
+ return *this;
+ }
};
-int main() {
+int calc1() {
Num<int> left = -1;
Num<int> right = 1;
Num<int> result = left + right;
return result.get();
}
+
+int calc2() {
+ Num<int> x = 3;
+ Num<int>::Rep<char> n = 10;
+ Num<int> result = x * n;
+ return result.get();
+}
More information about the cfe-commits
mailing list