def err_unexpected_friend : Error<
"friends can only be classes or functions">;
-def err_enum_friend : Error<
- "enum types cannot be friends">;
+def ext_enum_friend : ExtWarn<
+ "enumeration type %0 cannot be a friend">;
+def ext_nonclass_type_friend : ExtWarn<
+ "non-class type %0 cannot be a friend">;
def err_friend_is_member : Error<
"friends cannot be members of the declaring class">;
-def err_unelaborated_friend_type : Error<
+def ext_unelaborated_friend_type : ExtWarn<
"must specify '%select{struct|union|class|enum}0' to befriend %1">;
def err_qualified_friend_not_found : Error<
"no function named %0 with type %1 was found in the specified scope">;
QualType T = TSInfo->getType();
SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange();
- // C++03 [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.
- if (!getLangOptions().CPlusPlus0x && !T->isElaboratedTypeSpecifier()) {
- // If we evaluated the type to a record type, suggest putting
- // a tag in front.
- if (const RecordType *RT = T->getAs<RecordType>()) {
- RecordDecl *RD = RT->getDecl();
-
- std::string InsertionText = std::string(" ") + RD->getKindName();
-
- Diag(FriendLoc, diag::err_unelaborated_friend_type)
- << (unsigned) RD->getTagKind()
+ if (!getLangOptions().CPlusPlus0x) {
+ // C++03 [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.
+ if (!ActiveTemplateInstantiations.empty()) {
+ // Do not complain about the form of friend template types during
+ // template instantiation; we will already have complained when the
+ // template was declared.
+ } else if (!T->isElaboratedTypeSpecifier()) {
+ // If we evaluated the type to a record type, suggest putting
+ // a tag in front.
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ RecordDecl *RD = RT->getDecl();
+
+ std::string InsertionText = std::string(" ") + RD->getKindName();
+
+ Diag(TypeRange.getBegin(), diag::ext_unelaborated_friend_type)
+ << (unsigned) RD->getTagKind()
+ << T
+ << FixItHint::CreateInsertion(PP.getLocForEndOfToken(FriendLoc),
+ InsertionText);
+ } else {
+ Diag(FriendLoc, diag::ext_nonclass_type_friend)
+ << T
+ << SourceRange(FriendLoc, TypeRange.getEnd());
+ }
+ } else if (T->getAs<EnumType>()) {
+ Diag(FriendLoc, diag::ext_enum_friend)
<< T
- << SourceRange(FriendLoc)
- << FixItHint::CreateInsertion(TypeRange.getBegin(),
- InsertionText);
- return 0;
- } else {
- Diag(FriendLoc, diag::err_unexpected_friend)
<< SourceRange(FriendLoc, TypeRange.getEnd());
- return 0;
}
}
- // Enum types cannot be friends.
- if (T->getAs<EnumType>()) {
- Diag(FriendLoc, diag::err_enum_friend)
- << SourceRange(FriendLoc, TypeRange.getEnd());
- return 0;
- }
+ // C++0x [class.friend]p3:
+ // If the type specifier in a friend declaration designates a (possibly
+ // cv-qualified) class type, that class is declared as a friend; otherwise,
+ // the friend declaration is ignored.
+
+ // FIXME: C++0x has some syntactic restrictions on friend type declarations
+ // in [class.friend]p3 that we do not implement.
return FriendDecl::Create(Context, CurContext, FriendLoc, TSInfo, FriendLoc);
}
return DeclPtrTy();
}
- // Enum templates cannot be friends.
- if (TempParams.size() && T->getAs<EnumType>()) {
- Diag(DS.getTypeSpecTypeLoc(), diag::err_enum_friend)
- << SourceRange(DS.getFriendSpecLoc());
- return DeclPtrTy();
- }
-
// C++98 [class.friend]p1: A friend of a class is a function
// or class that is not a member of the class . . .
// This is fixed in DR77, which just barely didn't make the C++03
}
Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
- FriendDecl::FriendUnion FU;
-
// Handle friend type expressions by simply substituting template
- // parameters into the pattern type.
+ // parameters into the pattern type and checking the result.
if (TypeSourceInfo *Ty = D->getFriendType()) {
TypeSourceInfo *InstTy =
SemaRef.SubstType(Ty, TemplateArgs,
D->getLocation(), DeclarationName());
- if (!InstTy) return 0;
+ if (!InstTy)
+ return 0;
- // This assertion is valid because the source type was necessarily
- // an elaborated-type-specifier with a record tag.
- assert(getLangOptions().CPlusPlus0x || InstTy->getType()->isRecordType());
+ FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getFriendLoc(), InstTy);
+ if (!FD)
+ return 0;
+
+ FD->setAccess(AS_public);
+ Owner->addDecl(FD);
+ return FD;
+ }
+
+ NamedDecl *ND = D->getFriendDecl();
+ assert(ND && "friend decl must be a decl or a type!");
- FU = InstTy;
+ // FIXME: We have a problem here, because the nested call to Visit(ND)
+ // will inject the thing that the friend references into the current
+ // owner, which is wrong.
+ Decl *NewND;
- // Handle everything else by appropriate substitution.
+ // Hack to make this work almost well pending a rewrite.
+ if (D->wasSpecialization()) {
+ // Totally egregious hack to work around PR5866
+ return 0;
} else {
- NamedDecl *ND = D->getFriendDecl();
- assert(ND && "friend decl must be a decl or a type!");
-
- // FIXME: We have a problem here, because the nested call to Visit(ND)
- // will inject the thing that the friend references into the current
- // owner, which is wrong.
- Decl *NewND;
-
- // Hack to make this work almost well pending a rewrite.
- if (D->wasSpecialization()) {
- // Totally egregious hack to work around PR5866
- return 0;
- } else {
- NewND = Visit(ND);
- }
- if (!NewND) return 0;
-
- FU = cast<NamedDecl>(NewND);
+ NewND = Visit(ND);
}
+ if (!NewND) return 0;
FriendDecl *FD =
- FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), FU,
- D->getFriendLoc());
+ FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ cast<NamedDecl>(NewND), D->getFriendLoc());
FD->setAccess(AS_public);
Owner->addDecl(FD);
return FD;
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+template<typename T>
+class X0 {
+ friend T; // expected-warning{{non-class type 'T' cannot be a friend}}
+};
+
+class X1 { };
+enum E1 { };
+X0<X1> x0a;
+X0<X1 *> x0b;
+X0<int> x0c;
+X0<E1> x0d;
+
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+template<typename T>
+class X0 {
+ friend T;
+};
+
+class Y1 { };
+enum E1 { };
+X0<Y1> x0a;
+X0<Y1 *> x0b;
+X0<int> x0c;
+X0<E1> x0d;
+
+template<typename T>
+class X1 {
+ friend typename T::type; // expected-error{{no type named 'type' in 'Y1'}}
+};
+
+struct Y2 {
+ struct type { };
+};
+
+struct Y3 {
+ typedef int type;
+};
+
+X1<Y2> x1a;
+X1<Y3> x1b;
+X1<Y1> x1c; // expected-note{{in instantiation of template class 'X1<Y1>' requested here}}
class A {
friend class B {}; // expected-error {{cannot define a type in a friend declaration}}
- friend int; // expected-error {{friends can only be classes or functions}}
- friend B0; // expected-error {{must specify 'struct' to befriend}}
+ friend int; // expected-warning {{non-class type 'int' cannot be a friend}}
+ friend B0; // expected-warning {{must specify 'struct' to befriend}}
friend class C; // okay
};
friend union A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
friend enum A; // expected-error {{ISO C++ forbids forward references to 'enum' types}} \
- // expected-error {{enum types cannot be friends}}
+ // expected-warning {{cannot be a friend}}
};
template <class T> struct B { // expected-note {{previous use is here}}
template <class T> friend class A;
template <class T> friend class Undeclared;
- // FIXME: Diagnostic below could be (and was) better.
- template <class T> friend typename A<T>::Member; // expected-error {{classes or functions}}
+ template <class T> friend typename A<T>::Member; // expected-warning {{non-class type 'typename A<T>::Member' cannot be a friend}}
};
// 'A' here should refer to the declaration above.
friend class A;
- friend C; // expected-error {{must specify 'class' to befriend}}
- friend U; // expected-error {{must specify 'union' to befriend}}
- friend int; // expected-error {{friends can only be classes or functions}}
+ friend C; // expected-warning {{must specify 'class' to befriend}}
+ friend U; // expected-warning {{must specify 'union' to befriend}}
+ friend int; // expected-warning {{non-class type 'int' cannot be a friend}}
friend void myfunc();