def err_variadic_templates : Error<
"variadic templates are only allowed in C++0x">;
+
+// C++ declarations
+def err_friend_decl_defines_class : Error<
+ "cannot define a type in a friend declaration">;
// Language specific pragmas
// - Generic warnings
"static_assert expression is not an integral constant expression">;
def err_static_assert_failed : Error<"static_assert failed \"%0\"">;
-def err_friend_decl_defines_class : Error<
- "cannot define a type in a friend declaration">;
def err_unexpected_friend : Error<
"friends can only be classes or functions">;
def err_friend_is_member : Error<
def ext_friend_inner_class : Extension<
"C++ 98 does not allow inner classes as friends">;
def err_unelaborated_friend_type : Error<
- "must specify '%select{class|union}0' in a friend "
- "%select{class|union}0 declaration">;
+ "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">;
def err_introducing_special_friend : Error<
// 'struct foo :...' then this is a definition. Otherwise we have
// something like 'struct foo xyz', a reference.
Action::TagUseKind TUK;
- if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon)))
- TUK = Action::TUK_Definition;
- else if (Tok.is(tok::semi))
+ if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))) {
+ if (DS.isFriendSpecified()) {
+ // C++ [class.friend]p2:
+ // A class shall not be defined in a friend declaration.
+ Diag(Tok.getLocation(), diag::err_friend_decl_defines_class)
+ << SourceRange(DS.getFriendSpecLoc());
+
+ // Skip everything up to the semicolon, so that this looks like a proper
+ // friend class (or template thereof) declaration.
+ SkipUntil(tok::semi, true, true);
+ TUK = Action::TUK_Friend;
+ } else {
+ // Okay, this is a class definition.
+ TUK = Action::TUK_Definition;
+ }
+ } else if (Tok.is(tok::semi))
TUK = DS.isFriendSpecified() ? Action::TUK_Friend : Action::TUK_Declaration;
else
TUK = Action::TUK_Reference;
if (Tok.is(tok::semi)) {
ConsumeToken();
-
- if (DS.isFriendSpecified()) {
- Actions.ActOnFriendTypeDecl(CurScope, DS, move(TemplateParams));
- } else
- Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
-
+ Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
return;
}
Tag = dyn_cast<TagDecl>(static_cast<Decl *>(DS.getTypeRep()));
}
+ if (DS.isFriendSpecified()) {
+ // We have a "friend" declaration that does not have a declarator.
+ // Look at the type to see if the friend declaration was handled
+ // elsewhere (e.g., for friend classes and friend class templates).
+ // If not, produce a suitable diagnostic or go try to befriend the
+ // type itself.
+ QualType T;
+ if (DS.getTypeSpecType() == DeclSpec::TST_typename ||
+ DS.getTypeSpecType() == DeclSpec::TST_typeofType)
+ T = QualType::getFromOpaquePtr(DS.getTypeRep());
+ else if (DS.getTypeSpecType() == DeclSpec::TST_typeofExpr ||
+ DS.getTypeSpecType() == DeclSpec::TST_decltype)
+ T = ((Expr *)DS.getTypeRep())->getType();
+ else if (DS.getTypeSpecType() == DeclSpec::TST_class ||
+ DS.getTypeSpecType() == DeclSpec::TST_struct ||
+ DS.getTypeSpecType() == DeclSpec::TST_union)
+ return DeclPtrTy::make(Tag);
+
+ if (T.isNull()) {
+ // Fall through to diagnose this error, below.
+ } else if (const RecordType *RecordT = T->getAs<RecordType>()) {
+ // C++ [class.friend]p2:
+ // An elaborated-type-specifier shall be used in a friend declaration
+ // for a class.
+
+ // We have something like "friend C;", where C is the name of a
+ // class type but is missing an elaborated type specifier. Complain,
+ // but tell the user exactly how to fix the problem.
+ RecordDecl *RecordD = RecordT->getDecl();
+ Diag(DS.getTypeSpecTypeLoc(), diag::err_unelaborated_friend_type)
+ << (unsigned)RecordD->getTagKind()
+ << QualType(RecordT, 0)
+ << SourceRange(DS.getFriendSpecLoc())
+ << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
+ RecordD->getKindName() + std::string(" "));
+
+ // FIXME: We could go into ActOnTag to actually make the friend
+ // declaration happen at this point.
+ return DeclPtrTy();
+ }
+
+ if (!T.isNull() && T->isDependentType()) {
+ // Since T is a dependent type, handle it as a friend type
+ // declaration.
+ return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0));
+ }
+
+ // Complain about any non-dependent friend type here.
+ Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
+ << DS.getSourceRange();
+ return DeclPtrTy();
+ }
+
if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) {
if (!Record->getDeclName() && Record->isDefinition() &&
DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
if (Record->getDeclName() && getLangOptions().Microsoft)
return DeclPtrTy::make(Tag);
}
-
+
if (!DS.isMissingDeclaratorOk() &&
DS.getTypeSpecType() != DeclSpec::TST_error) {
// Warn about typedefs of enums without names, since this is an
= MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
(TemplateParameterList**)TemplateParameterLists.get(),
TemplateParameterLists.size())) {
- if (TUK == TUK_Friend) {
- // When declaring a friend template, we do want to match the
- // template parameters to the scope specifier, but don't go so far
- // as to try to declare a new template.
- } else if (TemplateParams->size() > 0) {
+ if (TemplateParams->size() > 0) {
// This is a declaration or definition of a class template (which may
// be a member of another template).
OwnedDecl = false;
break;
}
- // 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();
- }
-
// 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
return true;
}
+ Previous = LookupQualifiedName(SemanticContext, Name, LookupOrdinaryName,
+ true);
+ } else if (TUK == TUK_Friend) {
+ // C++ [namespace.memdef]p3:
+ // [...] When looking for a prior declaration of a class or a function
+ // declared as a friend, and when the name of the friend class or
+ // function is neither a qualified name nor a template-id, scopes outside
+ // the innermost enclosing namespace scope are not considered.
+ SemanticContext = CurContext;
+ while (!SemanticContext->isFileContext())
+ SemanticContext = SemanticContext->getLookupParent();
+
Previous = LookupQualifiedName(SemanticContext, Name, LookupOrdinaryName,
true);
} else {
// FIXME: If we had a scope specifier, we better have a previous template
// declaration!
- // If this is a friend declaration of an undeclared template,
- // create the template in the innermost namespace scope.
- if (TUK == TUK_Friend && !PrevClassTemplate) {
- while (!SemanticContext->isFileContext())
- SemanticContext = SemanticContext->getParent();
- }
-
CXXRecordDecl *NewClass =
CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc,
PrevClassTemplate?
(void)T;
// Set the access specifier.
- if (TUK == TUK_Friend)
- NewTemplate->setObjectOfFriendDecl(/* PreviouslyDeclared = */
- PrevClassTemplate != NULL);
- else
+ if (!Invalid && TUK != TUK_Friend)
SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
// Set the lexical context of these templates
if (TUK != TUK_Friend)
PushOnScopeChains(NewTemplate, S);
else {
- // We might be replacing an existing declaration in the lookup tables;
- // if so, borrow its access specifier.
- if (PrevClassTemplate)
+ if (PrevClassTemplate && PrevClassTemplate->getAccess() != AS_none) {
NewTemplate->setAccess(PrevClassTemplate->getAccess());
+ NewClass->setAccess(PrevClassTemplate->getAccess());
+ }
+ NewTemplate->setObjectOfFriendDecl(/* PreviouslyDeclared = */
+ PrevClassTemplate != NULL);
+
// Friend templates are visible in fairly strange ways.
if (!CurContext->isDependentContext()) {
DeclContext *DC = SemanticContext->getLookupContext();
PushOnScopeChains(NewTemplate, EnclosingScope,
/* AddToContext = */ false);
}
+
+ FriendDecl *Friend = FriendDecl::Create(Context, CurContext,
+ NewClass->getLocation(),
+ NewTemplate,
+ /*FIXME:*/NewClass->getLocation());
+ Friend->setAccess(AS_public);
+ CurContext->addDecl(Friend);
}
if (Invalid) {
// RUN: clang-cc -fsyntax-only -verify %s
+struct B0;
+
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 B; // expected-error {{must specify 'class' in a friend class declaration}}
+ friend B0; // expected-error {{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}}
// FIXME: a better error would be something like 'enum types cannot be friends'
- friend enum A; // expected-error {{ISO C++ forbids forward references to 'enum' types}}
+ friend enum A; // expected-error {{ISO C++ forbids forward references to 'enum' types}} \
+ // expected-error{{classes or functions}}
};
template <class T> struct B { // expected-note {{previous use is here}}
class B {
template <class T> friend class A;
template <class T> friend class Undeclared;
- template <class T> friend typename A<T>::Member; // expected-error {{friend type templates must use an elaborated type}}
+
+ // FIXME: Diagnostic below could be (and was) better.
+ template <class T> friend typename A<T>::Member; // expected-error {{classes or functions}}
};
// 'A' here should refer to the declaration above.
friend class A;
- friend C; // expected-error {{must specify 'class' in a friend class declaration}}
- friend U; // expected-error {{must specify 'union' in a friend union declaration}}
+ 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 void myfunc();
--- /dev/null
+// RUN: clang-cc -fsyntax-only %s
+
+// PR5057
+namespace std {
+ class X {
+ public:
+ template<typename T>
+ friend struct Y;
+ };
+}
+
+namespace std {
+ template<typename T>
+ struct Y
+ {
+ };
+}