r191064 - Switch the semantic DeclContext for a block-scope declaration of a function or
Richard Smith
richard-llvm at metafoo.co.uk
Thu Sep 19 18:15:31 PDT 2013
Author: rsmith
Date: Thu Sep 19 20:15:31 2013
New Revision: 191064
URL: http://llvm.org/viewvc/llvm-project?rev=191064&view=rev
Log:
Switch the semantic DeclContext for a block-scope declaration of a function or
variable from being the function to being the enclosing namespace scope (in
C++) or the TU (in C). This allows us to fix a selection of related issues
where we would build incorrect redeclaration chains for such declarations, and
fail to notice type mismatches.
Such declarations are put into a new IdentifierNamespace, IDNS_LocalExtern,
which is only found when searching scopes, and not found when searching
DeclContexts. Such a declaration is only made visible in its DeclContext if
there are no non-LocalExtern declarations.
Added:
cfe/trunk/test/CXX/basic/basic.link/p7.cpp
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/include/clang/AST/DeclBase.h
cfe/trunk/include/clang/Sema/Lookup.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaAccess.cpp
cfe/trunk/lib/Sema/SemaCodeComplete.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaLookup.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
cfe/trunk/test/CXX/drs/dr0xx.cpp
cfe/trunk/test/CodeGenCXX/mangle.cpp
cfe/trunk/test/Index/usrs.m
cfe/trunk/test/Sema/struct-decl.c
cfe/trunk/test/SemaCXX/blocks-1.cpp
cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp
cfe/trunk/test/SemaCXX/extern-c.cpp
cfe/trunk/test/SemaCXX/function-redecl.cpp
cfe/trunk/test/SemaCXX/warn-unreachable.cpp
cfe/trunk/www/cxx_dr_status.html
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Thu Sep 19 20:15:31 2013
@@ -873,7 +873,7 @@ public:
bool isLocalVarDecl() const {
if (getKind() != Decl::Var)
return false;
- if (const DeclContext *DC = getDeclContext())
+ if (const DeclContext *DC = getLexicalDeclContext())
return DC->getRedeclContext()->isFunctionOrMethod();
return false;
}
@@ -883,7 +883,7 @@ public:
bool isFunctionOrMethodVarDecl() const {
if (getKind() != Decl::Var)
return false;
- const DeclContext *DC = getDeclContext()->getRedeclContext();
+ const DeclContext *DC = getLexicalDeclContext()->getRedeclContext();
return DC->isFunctionOrMethod() && DC->getDeclKind() != Decl::Block;
}
@@ -959,7 +959,7 @@ public:
if (K == ParmVar || K == ImplicitParam)
return false;
- if (getDeclContext()->getRedeclContext()->isFileContext())
+ if (getLexicalDeclContext()->getRedeclContext()->isFileContext())
return true;
if (isStaticDataMember())
@@ -3472,10 +3472,8 @@ void Redeclarable<decl_type>::setPreviou
// If the declaration was previously visible, a redeclaration of it remains
// visible even if it wouldn't be visible by itself.
- // FIXME: Once we handle local extern decls properly, this should inherit
- // the visibility from MostRecent, not from PrevDecl.
static_cast<decl_type*>(this)->IdentifierNamespace |=
- PrevDecl->getIdentifierNamespace() &
+ MostRecent->getIdentifierNamespace() &
(Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type);
} else {
// Make this first.
Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Thu Sep 19 20:15:31 2013
@@ -159,7 +159,12 @@ public:
/// This declaration is a C++ operator declared in a non-class
/// context. All such operators are also in IDNS_Ordinary.
/// C++ lexical operator lookup looks for these.
- IDNS_NonMemberOperator = 0x0400
+ IDNS_NonMemberOperator = 0x0400,
+
+ /// This declaration is a function-local extern declaration of a
+ /// variable or function. This may also be IDNS_Ordinary if it
+ /// has been declared outside any function.
+ IDNS_LocalExtern = 0x0800
};
/// ObjCDeclQualifier - 'Qualifiers' written next to the return and
@@ -829,6 +834,32 @@ public:
bool isFunctionOrFunctionTemplate() const;
/// \brief Changes the namespace of this declaration to reflect that it's
+ /// a function-local extern declaration.
+ ///
+ /// These declarations appear in the lexical context of the extern
+ /// declaration, but in the semantic context of the enclosing namespace
+ /// scope.
+ void setLocalExternDecl() {
+ assert((IdentifierNamespace == IDNS_Ordinary ||
+ IdentifierNamespace == IDNS_OrdinaryFriend) &&
+ "namespace is not ordinary");
+
+ Decl *Prev = getPreviousDecl();
+ IdentifierNamespace &= ~IDNS_Ordinary;
+
+ IdentifierNamespace |= IDNS_LocalExtern;
+ if (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary)
+ IdentifierNamespace |= IDNS_Ordinary;
+ }
+
+ /// \brief Determine whether this is a block-scope declaration with linkage.
+ /// This will either be a local variable declaration declared 'extern', or a
+ /// local function declaration.
+ bool isLocalExternDecl() {
+ return IdentifierNamespace & IDNS_LocalExtern;
+ }
+
+ /// \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
@@ -838,22 +869,25 @@ public:
void setObjectOfFriendDecl(bool PerformFriendInjection = false) {
unsigned OldNS = IdentifierNamespace;
assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
- IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
+ IDNS_TagFriend | IDNS_OrdinaryFriend |
+ IDNS_LocalExtern)) &&
"namespace includes neither ordinary nor tag");
assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type |
- IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
+ IDNS_TagFriend | IDNS_OrdinaryFriend |
+ IDNS_LocalExtern)) &&
"namespace includes other than ordinary or tag");
Decl *Prev = getPreviousDecl();
- IdentifierNamespace = 0;
+ IdentifierNamespace &= ~(IDNS_Ordinary | IDNS_Tag | IDNS_Type);
+
if (OldNS & (IDNS_Tag | IDNS_TagFriend)) {
IdentifierNamespace |= IDNS_TagFriend;
- if (PerformFriendInjection ||
+ if (PerformFriendInjection ||
(Prev && Prev->getIdentifierNamespace() & IDNS_Tag))
IdentifierNamespace |= IDNS_Tag | IDNS_Type;
}
- if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) {
+ if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend | IDNS_LocalExtern)) {
IdentifierNamespace |= IDNS_OrdinaryFriend;
if (PerformFriendInjection ||
(Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary))
Modified: cfe/trunk/include/clang/Sema/Lookup.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Lookup.h?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Lookup.h (original)
+++ cfe/trunk/include/clang/Sema/Lookup.h Thu Sep 19 20:15:31 2013
@@ -613,6 +613,13 @@ public:
return Filter(*this);
}
+ void setFindLocalExtern(bool FindLocalExtern) {
+ if (FindLocalExtern)
+ IDNS |= Decl::IDNS_LocalExtern;
+ else
+ IDNS &= ~Decl::IDNS_LocalExtern;
+ }
+
private:
void diagnose() {
if (isAmbiguous())
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Sep 19 20:15:31 2013
@@ -1451,6 +1451,7 @@ public:
bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
DeclarationName Name,
SourceLocation Loc);
+ static bool adjustContextForLocalExternDecl(DeclContext *&DC);
void DiagnoseFunctionSpecifiers(const DeclSpec &DS);
void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R);
void CheckShadow(Scope *S, VarDecl *D);
@@ -6465,8 +6466,9 @@ public:
void
BuildVariableInstantiation(VarDecl *NewVar, VarDecl *OldVar,
const MultiLevelTemplateArgumentList &TemplateArgs,
- LateInstantiatedAttrVec *LateAttrs = 0,
- LocalInstantiationScope *StartingScope = 0,
+ LateInstantiatedAttrVec *LateAttrs,
+ DeclContext *Owner,
+ LocalInstantiationScope *StartingScope,
bool InstantiatingVarTemplate = false);
void InstantiateVariableInitializer(
VarDecl *Var, VarDecl *OldVar,
Modified: cfe/trunk/lib/Sema/SemaAccess.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAccess.cpp?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaAccess.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAccess.cpp Thu Sep 19 20:15:31 2013
@@ -1483,7 +1483,9 @@ void Sema::HandleDelayedAccessCheck(Dela
DeclContext *DC = D->getDeclContext();
if (FunctionDecl *FN = dyn_cast<FunctionDecl>(D)) {
- if (!DC->isFunctionOrMethod())
+ if (D->getLexicalDeclContext()->isFunctionOrMethod())
+ DC = D->getLexicalDeclContext();
+ else
DC = FN;
} else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) {
DC = cast<DeclContext>(TD->getTemplatedDecl());
Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Thu Sep 19 20:15:31 2013
@@ -715,8 +715,8 @@ unsigned ResultBuilder::getBasePriority(
return CCP_Unlikely;
// Context-based decisions.
- const DeclContext *DC = ND->getDeclContext()->getRedeclContext();
- if (DC->isFunctionOrMethod() || isa<BlockDecl>(DC)) {
+ const DeclContext *LexicalDC = ND->getLexicalDeclContext();
+ if (LexicalDC->isFunctionOrMethod()) {
// _cmd is relatively rare
if (const ImplicitParamDecl *ImplicitParam =
dyn_cast<ImplicitParamDecl>(ND))
@@ -726,6 +726,8 @@ unsigned ResultBuilder::getBasePriority(
return CCP_LocalDeclaration;
}
+
+ const DeclContext *DC = ND->getDeclContext()->getRedeclContext();
if (DC->isRecord() || isa<ObjCContainerDecl>(DC))
return CCP_MemberDeclaration;
@@ -876,8 +878,8 @@ void ResultBuilder::MaybeAddResult(Resul
for (; I != IEnd; ++I) {
// A tag declaration does not hide a non-tag declaration.
if (I->first->hasTagIdentifierNamespace() &&
- (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
- Decl::IDNS_ObjCProtocol)))
+ (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
+ Decl::IDNS_LocalExtern | Decl::IDNS_ObjCProtocol)))
continue;
// Protocols are in distinct namespaces from everything else.
@@ -1038,7 +1040,9 @@ void ResultBuilder::ExitScope() {
bool ResultBuilder::IsOrdinaryName(const NamedDecl *ND) const {
ND = cast<NamedDecl>(ND->getUnderlyingDecl());
- unsigned IDNS = Decl::IDNS_Ordinary;
+ // If name lookup finds a local extern declaration, then we are in a
+ // context where it behaves like an ordinary name.
+ unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern;
if (SemaRef.getLangOpts().CPlusPlus)
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member;
else if (SemaRef.getLangOpts().ObjC1) {
@@ -1056,7 +1060,7 @@ bool ResultBuilder::IsOrdinaryNonTypeNam
if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND))
return false;
- unsigned IDNS = Decl::IDNS_Ordinary;
+ unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern;
if (SemaRef.getLangOpts().CPlusPlus)
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member;
else if (SemaRef.getLangOpts().ObjC1) {
@@ -1083,7 +1087,7 @@ bool ResultBuilder::IsIntegralConstantVa
bool ResultBuilder::IsOrdinaryNonValueName(const NamedDecl *ND) const {
ND = cast<NamedDecl>(ND->getUnderlyingDecl());
- unsigned IDNS = Decl::IDNS_Ordinary;
+ unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern;
if (SemaRef.getLangOpts().CPlusPlus)
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace;
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Sep 19 20:15:31 2013
@@ -1020,12 +1020,12 @@ void Sema::PushOnScopeChains(NamedDecl *
if (AddToContext)
CurContext->addDecl(D);
- // Out-of-line definitions shouldn't be pushed into scope in C++.
- // Out-of-line variable and function definitions shouldn't even in C.
- if ((getLangOpts().CPlusPlus || isa<VarDecl>(D) || isa<FunctionDecl>(D)) &&
- D->isOutOfLine() &&
+ // Out-of-line definitions shouldn't be pushed into scope in C++, unless they
+ // are function-local declarations.
+ if (getLangOpts().CPlusPlus && D->isOutOfLine() &&
!D->getDeclContext()->getRedeclContext()->Equals(
- D->getLexicalDeclContext()->getRedeclContext()))
+ D->getLexicalDeclContext()->getRedeclContext()) &&
+ !D->getLexicalDeclContext()->isFunctionOrMethod())
return;
// Template instantiations should also not be pushed into scope.
@@ -2426,7 +2426,9 @@ bool Sema::MergeFunctionDecl(FunctionDec
? New->getTypeSourceInfo()->getType()->castAs<FunctionType>()
: NewType)->getResultType();
QualType ResQT;
- if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType)) {
+ if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType) &&
+ !((NewQType->isDependentType() || OldQType->isDependentType()) &&
+ New->isLocalExternDecl())) {
if (NewDeclaredReturnType->isObjCObjectPointerType() &&
OldDeclaredReturnType->isObjCObjectPointerType())
ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType);
@@ -2578,6 +2580,14 @@ bool Sema::MergeFunctionDecl(FunctionDec
if (OldQTypeForComparison == NewQType)
return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld);
+ if ((NewQType->isDependentType() || OldQType->isDependentType()) &&
+ New->isLocalExternDecl()) {
+ // It's OK if we couldn't merge types for a local function declaraton
+ // if either the old or new type is dependent. We'll merge the types
+ // when we instantiate the function.
+ return false;
+ }
+
// Fall through for conflicting redeclarations and redefinitions.
}
@@ -2710,7 +2720,7 @@ bool Sema::MergeFunctionDecl(FunctionDec
// local declaration will produce a hard error; if it doesn't
// remain visible, a single bogus local redeclaration (which is
// actually only a warning) could break all the downstream code.
- if (!New->getDeclContext()->isFunctionOrMethod())
+ if (!New->getLexicalDeclContext()->isFunctionOrMethod())
New->getIdentifier()->setBuiltinID(Builtin::NotBuiltin);
return false;
@@ -2820,18 +2830,21 @@ void Sema::MergeVarDeclTypes(VarDecl *Ne
NewArray->getElementType()))
MergedT = New->getType();
} else if (Old->getType()->isArrayType() &&
- New->getType()->isIncompleteArrayType()) {
+ New->getType()->isIncompleteArrayType()) {
const ArrayType *OldArray = Context.getAsArrayType(Old->getType());
const ArrayType *NewArray = Context.getAsArrayType(New->getType());
if (Context.hasSameType(OldArray->getElementType(),
NewArray->getElementType()))
MergedT = Old->getType();
- } else if (New->getType()->isObjCObjectPointerType()
- && Old->getType()->isObjCObjectPointerType()) {
- MergedT = Context.mergeObjCGCQualifiers(New->getType(),
- Old->getType());
+ } else if (New->getType()->isObjCObjectPointerType() &&
+ Old->getType()->isObjCObjectPointerType()) {
+ MergedT = Context.mergeObjCGCQualifiers(New->getType(),
+ Old->getType());
}
} else {
+ // C 6.2.7p2:
+ // All declarations that refer to the same object or function shall have
+ // compatible type.
MergedT = Context.mergeTypes(New->getType(), Old->getType());
}
if (MergedT.isNull()) {
@@ -4308,8 +4321,15 @@ NamedDecl *Sema::HandleDeclarator(Scope
// If this has an identifier and is not an invalid redeclaration or
// function template specialization, add it to the scope stack.
if (New->getDeclName() && AddToScope &&
- !(D.isRedeclaration() && New->isInvalidDecl()))
- PushOnScopeChains(New, S);
+ !(D.isRedeclaration() && New->isInvalidDecl())) {
+ // Only make a locally-scoped extern declaration visible if it is the first
+ // declaration of this entity. Qualified lookup for such an entity should
+ // only find this declaration if there is no visible declaration of it.
+ bool AddToContext = !D.isRedeclaration() || !New->isLocalExternDecl();
+ PushOnScopeChains(New, S, AddToContext);
+ if (!AddToContext)
+ CurContext->addHiddenDecl(New);
+ }
return New;
}
@@ -4808,6 +4828,30 @@ static bool shouldConsiderLinkage(const
llvm_unreachable("Unexpected context");
}
+/// Adjust the \c DeclContext for a function or variable that might be a
+/// function-local external declaration.
+bool Sema::adjustContextForLocalExternDecl(DeclContext *&DC) {
+ if (!DC->isFunctionOrMethod())
+ return false;
+
+ // If this is a local extern function or variable declared within a function
+ // template, don't add it into the enclosing namespace scope until it is
+ // instantiated; it might have a dependent type right now.
+ if (DC->isDependentContext())
+ return true;
+
+ // C++11 [basic.link]p7:
+ // When a block scope declaration of an entity with linkage is not found to
+ // refer to some other declaration, then that entity is a member of the
+ // innermost enclosing namespace.
+ //
+ // Per C++11 [namespace.def]p6, the innermost enclosing namespace is a
+ // semantically-enclosing namespace, not a lexically-enclosing one.
+ while (!DC->isFileContext() && !isa<LinkageSpecDecl>(DC))
+ DC = DC->getParent();
+ return true;
+}
+
NamedDecl *
Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
@@ -4820,6 +4864,10 @@ Sema::ActOnVariableDeclarator(Scope *S,
VarDecl::StorageClass SC =
StorageClassSpecToVarDeclStorageClass(D.getDeclSpec());
+ DeclContext *OriginalDC = DC;
+ bool IsLocalExternDecl = SC == SC_Extern &&
+ adjustContextForLocalExternDecl(DC);
+
if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16) {
// OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and
// half array type (unless the cl_khr_fp16 extension is enabled).
@@ -5150,6 +5198,9 @@ Sema::ActOnVariableDeclarator(Scope *S,
if (NewTemplate)
NewTemplate->setLexicalDeclContext(CurContext);
+ if (IsLocalExternDecl)
+ NewVD->setLocalExternDecl();
+
if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) {
if (NewVD->hasLocalStorage()) {
// C++11 [dcl.stc]p4:
@@ -5277,7 +5328,7 @@ Sema::ActOnVariableDeclarator(Scope *S,
// scope and are out-of-semantic-context declarations (if the new
// declaration has linkage).
FilterLookupForScope(
- Previous, DC, S, shouldConsiderLinkage(NewVD),
+ Previous, OriginalDC, S, shouldConsiderLinkage(NewVD),
IsExplicitSpecialization || IsVariableTemplateSpecialization);
// Check whether the previous declaration is in the same block scope. This
@@ -5286,7 +5337,7 @@ Sema::ActOnVariableDeclarator(Scope *S,
NewVD->isLocalVarDecl() && NewVD->hasExternalStorage())
NewVD->setPreviousDeclInSameBlockScope(
Previous.isSingleResult() && !Previous.isShadowed() &&
- isDeclInScope(Previous.getFoundDecl(), DC, S, false));
+ isDeclInScope(Previous.getFoundDecl(), OriginalDC, S, false));
if (!getLangOpts().CPlusPlus) {
D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
@@ -5543,12 +5594,8 @@ static bool checkForConflictWithNonVisib
LookupResult &Previous) {
if (!S.getLangOpts().CPlusPlus) {
// In C, when declaring a global variable, look for a corresponding 'extern'
- // variable declared in function scope.
- //
- // FIXME: The corresponding case in C++ does not work. We should instead
- // set the semantic DC for an extern local variable to be the innermost
- // enclosing namespace, and ensure they are only found by redeclaration
- // lookup.
+ // variable declared in function scope. We don't need this in C++, because
+ // we find local extern decls in the surrounding file-scope DeclContext.
if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
if (NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName())) {
Previous.clear();
@@ -6032,6 +6079,7 @@ static NamedDecl *DiagnoseInvalidRedecla
bool FDisConst = MD && MD->isConst();
bool IsMember = MD || !IsLocalFriend;
+ // FIXME: These notes are poorly worded for the local friend case.
if (unsigned Idx = NearMatch->second) {
ParmVarDecl *FDParam = FD->getParamDecl(Idx-1);
SourceLocation Loc = FDParam->getTypeSpecStartLoc();
@@ -6455,6 +6503,9 @@ Sema::ActOnFunctionDeclarator(Scope *S,
bool isVirtualOkay = false;
+ DeclContext *OriginalDC = DC;
+ bool IsLocalExternDecl = adjustContextForLocalExternDecl(DC);
+
FunctionDecl *NewFD = CreateNewFunctionDecl(*this, D, DC, R, TInfo, SC,
isVirtualOkay);
if (!NewFD) return 0;
@@ -6462,6 +6513,14 @@ Sema::ActOnFunctionDeclarator(Scope *S,
if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer())
NewFD->setTopLevelDeclInObjCContainer();
+ // Set the lexical context. If this is a function-scope declaration, or has a
+ // C++ scope specifier, or is the object of a friend declaration, the lexical
+ // context will be different from the semantic context.
+ NewFD->setLexicalDeclContext(CurContext);
+
+ if (IsLocalExternDecl)
+ NewFD->setLocalExternDecl();
+
if (getLangOpts().CPlusPlus) {
bool isInline = D.getDeclSpec().isInlineSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
@@ -6489,12 +6548,7 @@ Sema::ActOnFunctionDeclarator(Scope *S,
isFunctionTemplateSpecialization = false;
if (D.isInvalidType())
NewFD->setInvalidDecl();
-
- // Set the lexical context. If the declarator has a C++
- // scope specifier, or is the object of a friend declaration, the
- // lexical context will be different from the semantic context.
- NewFD->setLexicalDeclContext(CurContext);
-
+
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
bool Invalid = false;
@@ -6750,7 +6804,7 @@ Sema::ActOnFunctionDeclarator(Scope *S,
}
// Filter out previous declarations that don't match the scope.
- FilterLookupForScope(Previous, DC, S, shouldConsiderLinkage(NewFD),
+ FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewFD),
isExplicitSpecialization ||
isFunctionTemplateSpecialization);
@@ -9232,21 +9286,21 @@ static bool ShouldWarnAboutMissingProtot
// Don't warn for OpenCL kernels.
if (FD->hasAttr<OpenCLKernelAttr>())
return false;
-
+
bool MissingPrototype = true;
for (const FunctionDecl *Prev = FD->getPreviousDecl();
Prev; Prev = Prev->getPreviousDecl()) {
// Ignore any declarations that occur in function or method
// scope, because they aren't visible from the header.
- if (Prev->getDeclContext()->isFunctionOrMethod())
+ if (Prev->getLexicalDeclContext()->isFunctionOrMethod())
continue;
-
+
MissingPrototype = !Prev->getType()->isFunctionProtoType();
if (FD->getNumParams() == 0)
PossibleZeroParamPrototype = Prev;
break;
}
-
+
return MissingPrototype;
}
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Sep 19 20:15:31 2013
@@ -438,9 +438,9 @@ bool Sema::MergeCXXFunctionDecl(Function
// declaration (not even to the same value).
//
// C++ [dcl.fct.default]p6:
- // Except for member functions of class templates, the default arguments
- // in a member function definition that appears outside of the class
- // definition are added to the set of default arguments provided by the
+ // Except for member functions of class templates, the default arguments
+ // in a member function definition that appears outside of the class
+ // definition are added to the set of default arguments provided by the
// member function declaration in the class definition.
for (unsigned p = 0, NumParams = Old->getNumParams(); p < NumParams; ++p) {
ParmVarDecl *OldParam = Old->getParamDecl(p);
@@ -450,9 +450,18 @@ bool Sema::MergeCXXFunctionDecl(Function
bool NewParamHasDfl = NewParam->hasDefaultArg();
NamedDecl *ND = Old;
- if (S && !isDeclInScope(ND, New->getDeclContext(), S))
+
+ // The declaration context corresponding to the scope is the semantic
+ // parent, unless this is a local function declaration, in which case
+ // it is that surrounding function.
+ DeclContext *ScopeDC = New->getLexicalDeclContext();
+ if (!ScopeDC->isFunctionOrMethod())
+ ScopeDC = New->getDeclContext();
+ if (S && !isDeclInScope(ND, ScopeDC, S) &&
+ !New->getDeclContext()->isRecord())
// Ignore default parameters of old decl if they are not in
- // the same scope.
+ // the same scope and this is not an out-of-line definition of
+ // a member function.
OldParamHasDfl = false;
if (OldParamHasDfl && NewParamHasDfl) {
@@ -11486,6 +11495,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl
// declared the function in, if we were permitted to, for error recovery.
DC = FunctionContainingLocalClass;
}
+ adjustContextForLocalExternDecl(DC);
// C++ [class.friend]p6:
// A function can be defined in a friend declaration of a class if and
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Sep 19 20:15:31 2013
@@ -2459,7 +2459,7 @@ bool Sema::UseArgumentDependentLookup(co
// turn off ADL anyway).
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
- else if (D->getDeclContext()->isFunctionOrMethod())
+ else if (D->getLexicalDeclContext()->isFunctionOrMethod())
return false;
// C++0x [basic.lookup.argdep]p3:
Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Thu Sep 19 20:15:31 2013
@@ -223,6 +223,8 @@ static inline unsigned getIDNS(Sema::Loo
if (Redeclaration)
IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend;
}
+ if (Redeclaration)
+ IDNS |= Decl::IDNS_LocalExtern;
break;
case Sema::LookupOperatorName:
@@ -847,6 +849,26 @@ static std::pair<DeclContext *, bool> fi
return std::make_pair(Lexical, false);
}
+namespace {
+/// An RAII object to specify that we want to find block scope extern
+/// declarations.
+struct FindLocalExternScope {
+ FindLocalExternScope(LookupResult &R)
+ : R(R), OldFindLocalExtern(R.getIdentifierNamespace() &
+ Decl::IDNS_LocalExtern) {
+ R.setFindLocalExtern(R.getIdentifierNamespace() & Decl::IDNS_Ordinary);
+ }
+ void restore() {
+ R.setFindLocalExtern(OldFindLocalExtern);
+ }
+ ~FindLocalExternScope() {
+ restore();
+ }
+ LookupResult &R;
+ bool OldFindLocalExtern;
+};
+}
+
bool Sema::CppLookupName(LookupResult &R, Scope *S) {
assert(getLangOpts().CPlusPlus && "Can perform only C++ lookup");
@@ -891,6 +913,10 @@ bool Sema::CppLookupName(LookupResult &R
bool VisitedUsingDirectives = false;
bool LeftStartingScope = false;
DeclContext *OutsideOfTemplateParamDC = 0;
+
+ // When performing a scope lookup, we want to find local extern decls.
+ FindLocalExternScope FindLocals(R);
+
for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) {
DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity());
@@ -1046,7 +1072,12 @@ bool Sema::CppLookupName(LookupResult &R
UDirs.visitScopeChain(Initial, S);
UDirs.done();
}
-
+
+ // If we're not performing redeclaration lookup, do not look for local
+ // extern declarations outside of a function scope.
+ if (!R.isForRedeclaration())
+ FindLocals.restore();
+
// Lookup namespace scope, and global scope.
// Unqualified name lookup in C++ requires looking into scopes
// that aren't strictly lexical, and therefore we walk through the
@@ -1292,6 +1323,9 @@ bool Sema::LookupName(LookupResult &R, S
S = S->getParent();
}
+ // When performing a scope lookup, we want to find local extern decls.
+ FindLocalExternScope FindLocals(R);
+
// Scan up the scope chain looking for a decl that matches this
// identifier that is in the appropriate namespace. This search
// should not take long, as shadowing of names is uncommon, and
@@ -1361,6 +1395,7 @@ bool Sema::LookupName(LookupResult &R, S
R.resolveKind();
}
+
return true;
}
} else {
@@ -2858,7 +2893,11 @@ void Sema::ArgumentDependentLookup(Decla
NamedDecl *D = *I;
// 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) {
+ if ((D->getIdentifierNamespace() & Decl::IDNS_Ordinary) == 0) {
+ // If it's neither ordinarily visible nor a friend, we can't find it.
+ if ((D->getIdentifierNamespace() & Decl::IDNS_OrdinaryFriend) == 0)
+ continue;
+
bool DeclaredInAssociatedClass = false;
for (Decl *DI = D; DI; DI = DI->getPreviousDecl()) {
DeclContext *LexDC = DI->getLexicalDeclContext();
@@ -3160,6 +3199,7 @@ static void LookupVisibleDecls(Scope *S,
(!S->getParent() &&
!Visited.alreadyVisitedContext((DeclContext *)S->getEntity())) ||
((DeclContext *)S->getEntity())->isFunctionOrMethod()) {
+ FindLocalExternScope FindLocals(Result);
// Walk through the declarations in this Scope.
for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
D != DEnd; ++D) {
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Sep 19 20:15:31 2013
@@ -347,8 +347,12 @@ Decl *TemplateDeclInstantiator::VisitVar
return 0;
}
+ DeclContext *DC = Owner;
+ if (D->isLocalExternDecl())
+ SemaRef.adjustContextForLocalExternDecl(DC);
+
// Build the instantiated declaration.
- VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, D->getInnerLocStart(),
+ VarDecl *Var = VarDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
D->getLocation(), D->getIdentifier(),
DI->getType(), DI, D->getStorageClass());
@@ -361,7 +365,7 @@ Decl *TemplateDeclInstantiator::VisitVar
if (SubstQualifier(D, Var))
return 0;
- SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs,
+ SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, Owner,
StartingScope, InstantiatingVarTemplate);
return Var;
}
@@ -1199,11 +1203,13 @@ Decl *TemplateDeclInstantiator::VisitFun
}
// If we're instantiating a local function declaration, put the result
- // in the owner; otherwise we need to find the instantiated context.
+ // in the enclosing namespace; otherwise we need to find the instantiated
+ // context.
DeclContext *DC;
- if (D->getDeclContext()->isFunctionOrMethod())
+ if (D->isLocalExternDecl()) {
DC = Owner;
- else if (isFriend && QualifierLoc) {
+ SemaRef.adjustContextForLocalExternDecl(DC);
+ } else if (isFriend && QualifierLoc) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
DC = SemaRef.computeDeclContext(SS);
@@ -1227,8 +1233,11 @@ Decl *TemplateDeclInstantiator::VisitFun
if (QualifierLoc)
Function->setQualifierInfo(QualifierLoc);
+ if (D->isLocalExternDecl())
+ Function->setLocalExternDecl();
+
DeclContext *LexicalDC = Owner;
- if (!isFriend && D->isOutOfLine()) {
+ if (!isFriend && D->isOutOfLine() && !D->isLocalExternDecl()) {
assert(D->getDeclContext()->isFileContext());
LexicalDC = D->getDeclContext();
}
@@ -1294,8 +1303,11 @@ Decl *TemplateDeclInstantiator::VisitFun
bool isExplicitSpecialization = false;
- LookupResult Previous(SemaRef, Function->getDeclName(), SourceLocation(),
- Sema::LookupOrdinaryName, Sema::ForRedeclaration);
+ LookupResult Previous(
+ SemaRef, Function->getDeclName(), SourceLocation(),
+ D->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage
+ : Sema::LookupOrdinaryName,
+ Sema::ForRedeclaration);
if (DependentFunctionTemplateSpecializationInfo *Info
= D->getDependentSpecializationInfo()) {
@@ -1427,6 +1439,9 @@ Decl *TemplateDeclInstantiator::VisitFun
}
}
+ if (Function->isLocalExternDecl() && !Function->getPreviousDecl())
+ DC->makeDeclVisibleInContext(PrincipalDecl);
+
if (Function->isOverloadedOperator() && !DC->isRecord() &&
PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary))
PrincipalDecl->setNonMemberOperator();
@@ -2358,7 +2373,7 @@ Decl *TemplateDeclInstantiator::VisitVar
return 0;
SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs,
- StartingScope);
+ Owner, StartingScope);
return Var;
}
@@ -2680,7 +2695,7 @@ TemplateDeclInstantiator::InstantiateVar
if (VarDecl *Def = PartialSpec->getDefinition(SemaRef.getASTContext()))
PartialSpec = cast<VarTemplatePartialSpecializationDecl>(Def);
SemaRef.BuildVariableInstantiation(InstPartialSpec, PartialSpec, TemplateArgs,
- LateAttrs, StartingScope);
+ LateAttrs, Owner, StartingScope);
InstPartialSpec->setInit(PartialSpec->getInit());
return InstPartialSpec;
@@ -3335,13 +3350,19 @@ VarTemplateSpecializationDecl *Sema::Com
void Sema::BuildVariableInstantiation(
VarDecl *NewVar, VarDecl *OldVar,
const MultiLevelTemplateArgumentList &TemplateArgs,
- LateInstantiatedAttrVec *LateAttrs, LocalInstantiationScope *StartingScope,
+ LateInstantiatedAttrVec *LateAttrs, DeclContext *Owner,
+ LocalInstantiationScope *StartingScope,
bool InstantiatingVarTemplate) {
+ // If we are instantiating a local extern declaration, the
+ // instantiation belongs lexically to the containing function.
// If we are instantiating a static data member defined
// out-of-line, the instantiation will have the same lexical
// context (which will be a namespace scope) as the template.
- if (OldVar->isOutOfLine())
+ if (OldVar->isLocalExternDecl()) {
+ NewVar->setLocalExternDecl();
+ NewVar->setLexicalDeclContext(Owner);
+ } else if (OldVar->isOutOfLine())
NewVar->setLexicalDeclContext(OldVar->getLexicalDeclContext());
NewVar->setTSCSpec(OldVar->getTSCSpec());
NewVar->setInitStyle(OldVar->getInitStyle());
@@ -3374,11 +3395,13 @@ void Sema::BuildVariableInstantiation(
if (NewVar->hasAttrs())
CheckAlignasUnderalignment(NewVar);
- LookupResult Previous(*this, NewVar->getDeclName(), NewVar->getLocation(),
- Sema::LookupOrdinaryName, Sema::ForRedeclaration);
+ LookupResult Previous(
+ *this, NewVar->getDeclName(), NewVar->getLocation(),
+ NewVar->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage
+ : Sema::LookupOrdinaryName,
+ Sema::ForRedeclaration);
- if (NewVar->getLexicalDeclContext()->isFunctionOrMethod() &&
- OldVar->getPreviousDecl()) {
+ if (NewVar->isLocalExternDecl() && OldVar->getPreviousDecl()) {
// We have a previous declaration. Use that one, so we merge with the
// right type.
if (NamedDecl *NewPrev = FindInstantiatedDecl(
@@ -3389,13 +3412,13 @@ void Sema::BuildVariableInstantiation(
LookupQualifiedName(Previous, NewVar->getDeclContext(), false);
CheckVariableDeclaration(NewVar, Previous);
- if (OldVar->isOutOfLine()) {
- OldVar->getLexicalDeclContext()->addDecl(NewVar);
- if (!InstantiatingVarTemplate)
+ if (!InstantiatingVarTemplate) {
+ NewVar->getLexicalDeclContext()->addHiddenDecl(NewVar);
+ if (!NewVar->isLocalExternDecl() || !NewVar->getPreviousDecl())
NewVar->getDeclContext()->makeDeclVisibleInContext(NewVar);
- } else {
- if (!InstantiatingVarTemplate)
- NewVar->getDeclContext()->addDecl(NewVar);
+ }
+
+ if (!OldVar->isOutOfLine()) {
if (NewVar->getDeclContext()->isFunctionOrMethod())
CurrentInstantiationScope->InstantiatedLocal(OldVar, NewVar);
}
Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Thu Sep 19 20:15:31 2013
@@ -946,7 +946,13 @@ ASTDeclReader::RedeclarableResult ASTDec
VD->VarDeclBits.ARCPseudoStrong = Record[Idx++];
VD->VarDeclBits.IsConstexpr = Record[Idx++];
VD->VarDeclBits.PreviousDeclInSameBlockScope = Record[Idx++];
- VD->setCachedLinkage(Linkage(Record[Idx++]));
+ Linkage VarLinkage = Linkage(Record[Idx++]);
+ VD->setCachedLinkage(VarLinkage);
+
+ // Reconstruct the one piece of the IdentifierNamespace that we need.
+ if (VarLinkage != NoLinkage &&
+ VD->getLexicalDeclContext()->isFunctionOrMethod())
+ VD->setLocalExternDecl();
// Only true variables (not parameters or implicit parameters) can be merged.
if (VD->getKind() != Decl::ParmVar && VD->getKind() != Decl::ImplicitParam)
@@ -2199,8 +2205,6 @@ void ASTDeclReader::attachPreviousDecl(D
//
// FIXME: In this case, the declaration should only be visible if a module
// that makes it visible has been imported.
- // FIXME: This is not correct in the case where previous is a local extern
- // declaration and D is a friend declaraton.
D->IdentifierNamespace |=
previous->IdentifierNamespace &
(Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type);
Added: cfe/trunk/test/CXX/basic/basic.link/p7.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.link/p7.cpp?rev=191064&view=auto
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.link/p7.cpp (added)
+++ cfe/trunk/test/CXX/basic/basic.link/p7.cpp Thu Sep 19 20:15:31 2013
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -verify -std=c++1y %s
+
+// Example from the standard.
+namespace X {
+ void p() {
+ q(); // expected-error {{undeclared}}
+ extern void q();
+ }
+ void middle() {
+ q(); // expected-error {{undeclared}}
+ }
+ void q() { /*...*/ }
+ void bottom() {
+ q();
+ }
+}
+int q();
+
+namespace Test1 {
+ void f() {
+ extern int a; // expected-note {{previous}}
+ int g(void); // expected-note {{previous}}
+ }
+ double a; // expected-error {{different type: 'double' vs 'int'}}
+ double g(); // expected-error {{differ only in their return type}}
+}
+
+namespace Test2 {
+ void f() {
+ extern int a; // expected-note {{previous}}
+ int g(void); // expected-note {{previous}}
+ }
+ void h() {
+ extern double a; // expected-error {{different type: 'double' vs 'int'}}
+ double g(void); // expected-error {{differ only in their return type}}
+ }
+}
+
+namespace Test3 {
+ constexpr void (*f())() {
+ void h();
+ return &h;
+ }
+ constexpr void (*g())() {
+ void h();
+ return &h;
+ }
+ static_assert(f() == g(), "");
+}
+
+namespace Test4 {
+ template<typename T>
+ constexpr void (*f())() {
+ void h();
+ return &h;
+ }
+ static_assert(f<int>() == f<char>(), "");
+ void h();
+ static_assert(f<int>() == &h, "");
+}
+
+namespace Test5 {
+ constexpr auto f() -> void (*)() {
+ void g();
+ struct X {
+ friend void g();
+ static constexpr auto h() -> void (*)() { return g; }
+ };
+ return X::h();
+ }
+ void g();
+ static_assert(f() == g, "");
+}
Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp Thu Sep 19 20:15:31 2013
@@ -61,6 +61,8 @@ namespace test6 {
int x = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
}
int y = sizeof(array);
+ extern int array[];
+ int z = sizeof(array);
}
}
@@ -71,6 +73,19 @@ namespace test7 {
int x = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
}
int y = sizeof(array);
+ extern int array[];
+ int z = sizeof(array);
+}
+
+namespace test8 {
+ extern int array[];
+ void test() {
+ extern int array[100];
+ int x = sizeof(array);
+ }
+ int y = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+ extern int array[];
+ int z = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
}
namespace dependent {
@@ -143,10 +158,52 @@ namespace dependent {
}
template<typename T> void n() {
- extern T n_var;
+ extern T n_var; // expected-error {{redefinition of 'n_var' with a different type: 'double' vs 'int'}} expected-note {{previous}}
+ extern T n_fn(); // expected-error {{functions that differ only in their return type cannot be overloaded}} expected-note {{previous}}
}
template void n<int>();
- // FIXME: Diagnose this!
- float n_var;
- template void n<double>();
+ template void n<double>(); // expected-note {{in instantiation of}}
+
+ template<typename T> void o() {
+ extern T o_var; // expected-note {{previous}}
+ extern T o_fn(); // expected-note {{previous}}
+ }
+ template void o<int>();
+ float o_var; // expected-error {{redefinition of 'o_var' with a different type: 'float' vs 'int'}}
+ float o_fn(); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+
+ int p_var;
+ int p_fn();
+ template<typename T> void p() {
+ extern T p_var;
+ extern T p_fn();
+ }
+}
+
+namespace use_outside_ns {
+ namespace A {
+ extern int a[3];
+ extern int b[];
+ extern int c[3];
+ void f() {
+ extern int a[];
+ extern int b[3];
+ }
+ template<typename T> void x() {
+ extern T c;
+ extern T d;
+ }
+ extern int d[3];
+ template void x<int[]>();
+ }
+ int w = sizeof(A::a);
+ int x = sizeof(A::b); // expected-error {{incomplete}}
+ int y = sizeof(A::c);
+ int z = sizeof(A::d);
+ namespace A {
+ int g() { return sizeof(a); }
+ int h() { return sizeof(b); } // expected-error {{incomplete}}
+ int i() { return sizeof(c); }
+ int j() { return sizeof(d); }
+ }
}
Modified: cfe/trunk/test/CXX/drs/dr0xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr0xx.cpp?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr0xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr0xx.cpp Thu Sep 19 20:15:31 2013
@@ -280,7 +280,7 @@ namespace dr27 { // dr27: yes
// dr28: na
-namespace dr29 { // dr29: no
+namespace dr29 { // dr29: 3.4
void dr29_f0(); // expected-note {{here}}
void g0() { void dr29_f0(); }
extern "C++" void g0_cxx() { void dr29_f0(); }
@@ -291,17 +291,14 @@ namespace dr29 { // dr29: no
extern "C" void g1_c() { void dr29_f1(); }
extern "C++" void g1_cxx() { void dr29_f1(); } // expected-error {{different language linkage}}
- // FIXME: We should reject this.
- void g2() { void dr29_f2(); }
- extern "C" void dr29_f2();
-
- // FIXME: We should reject this.
- extern "C" void g3() { void dr29_f3(); }
- extern "C++" void dr29_f3();
-
- // FIXME: We should reject this.
- extern "C++" void g4() { void dr29_f4(); }
- extern "C" void dr29_f4();
+ void g2() { void dr29_f2(); } // expected-note {{here}}
+ extern "C" void dr29_f2(); // expected-error {{different language linkage}}
+
+ extern "C" void g3() { void dr29_f3(); } // expected-note {{here}}
+ extern "C++" void dr29_f3(); // expected-error {{different language linkage}}
+
+ extern "C++" void g4() { void dr29_f4(); } // expected-note {{here}}
+ extern "C" void dr29_f4(); // expected-error {{different language linkage}}
extern "C" void g5();
extern "C++" void dr29_f5();
Modified: cfe/trunk/test/CodeGenCXX/mangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle.cpp?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/mangle.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/mangle.cpp Thu Sep 19 20:15:31 2013
@@ -9,7 +9,7 @@ struct Y { };
// CHECK: @_ZGVZN1N1gEvE1a = internal global
//CHECK: @pr5966_i = external global
-//CHECK: @_ZL8pr5966_i = internal global
+//CHECK: @_ZL8pr5966_j = internal global
// CHECK-LABEL: define zeroext i1 @_ZplRK1YRA100_P1X
bool operator+(const Y&, X* (&xs)[100]) { return false; }
@@ -314,10 +314,10 @@ void pr5966_foo() {
pr5966_i = 0;
}
-static int pr5966_i;
+static int pr5966_j;
void pr5966_bar() {
- pr5966_i = 0;
+ pr5966_j = 0;
}
namespace test0 {
@@ -652,10 +652,10 @@ namespace test24 {
foo();
}
- static char foo() {}
+ static char bar() {}
void test1() {
- // CHECK: call signext i8 @_ZN6test24L3fooEv()
- foo();
+ // CHECK: call signext i8 @_ZN6test24L3barEv()
+ bar();
}
}
Modified: cfe/trunk/test/Index/usrs.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/usrs.m?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/test/Index/usrs.m (original)
+++ cfe/trunk/test/Index/usrs.m Thu Sep 19 20:15:31 2013
@@ -118,7 +118,7 @@ int test_multi_declaration(void) {
// CHECK: usrs.m c:objc(cs)Foo Extent=[34:1 - 45:2]
// CHECK: usrs.m c:objc(cs)Foo(im)godzilla Extent=[35:1 - 39:2]
// CHECK: usrs.m c:usrs.m at 402objc(cs)Foo(im)godzilla at a Extent=[36:3 - 36:19]
-// CHECK: usrs.m c:objc(cs)Foo(im)godzilla at z Extent=[37:3 - 37:15]
+// CHECK: usrs.m c:@z Extent=[37:3 - 37:15]
// CHECK: usrs.m c:objc(cs)Foo(cm)kingkong Extent=[40:1 - 43:2]
// CHECK: usrs.m c:usrs.m at 470objc(cs)Foo(cm)kingkong at local_var Extent=[41:3 - 41:16]
// CHECK: usrs.m c:objc(cs)Foo(py)d1 Extent=[44:1 - 44:15]
Modified: cfe/trunk/test/Sema/struct-decl.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/struct-decl.c?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/test/Sema/struct-decl.c (original)
+++ cfe/trunk/test/Sema/struct-decl.c Thu Sep 19 20:15:31 2013
@@ -57,3 +57,12 @@ const struct test2 { // expected-warning
inline struct test3 { // expected-error {{'inline' can only appear on functions}}
int x;
};
+
+struct hiding_1 {};
+struct hiding_2 {};
+void test_hiding() {
+ struct hiding_1 *hiding_1();
+ extern struct hiding_2 *hiding_2;
+ struct hiding_1 *p = hiding_1();
+ struct hiding_2 *q = hiding_2;
+}
Modified: cfe/trunk/test/SemaCXX/blocks-1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/blocks-1.cpp?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/blocks-1.cpp (original)
+++ cfe/trunk/test/SemaCXX/blocks-1.cpp Thu Sep 19 20:15:31 2013
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks -std=c++11
-// expected-no-diagnostics
+// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks -std=c++1y
extern "C" int exit(int);
@@ -57,3 +56,18 @@ namespace rdar11055105 {
foo(a);
};
}
+
+namespace LocalDecls {
+ void f() {
+ (void) ^{
+ extern int a; // expected-note {{previous}}
+ extern int b(); // expected-note {{previous}}
+ };
+ }
+ void g() {
+ (void) ^{
+ extern float a; // expected-error {{different type}}
+ extern float b(); // expected-error {{cannot be overloaded}}
+ };
+ }
+}
Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp Thu Sep 19 20:15:31 2013
@@ -36,10 +36,10 @@ namespace reference {
};
void call() {
- void f(const int&);
+ one f(const int&);
f({1});
- void g(int&); // expected-note {{passing argument}}
+ one g(int&); // expected-note {{passing argument}}
g({1}); // expected-error {{cannot bind to an initializer list temporary}}
int i = 0;
g({i});
Modified: cfe/trunk/test/SemaCXX/extern-c.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/extern-c.cpp?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/extern-c.cpp (original)
+++ cfe/trunk/test/SemaCXX/extern-c.cpp Thu Sep 19 20:15:31 2013
@@ -29,16 +29,27 @@ namespace test3 {
}
}
-extern "C" {
- void test4_f() {
- extern int test4_b; // expected-note {{declared with C language linkage here}}
+namespace N {
+ extern "C" {
+ void test4_f() {
+ extern int test4_b; // expected-note {{declared with C language linkage here}}
+ }
}
}
static float test4_b; // expected-error {{declaration of 'test4_b' in global scope conflicts with declaration with C language linkage}}
extern "C" {
- void test5_f() {
- extern int test5_b; // expected-note {{declared with C language linkage here}}
+ void test4c_f() {
+ extern int test4_c; // expected-note {{previous}}
+ }
+}
+static float test4_c; // expected-error {{redefinition of 'test4_c' with a different type: 'float' vs 'int'}}
+
+namespace N {
+ extern "C" {
+ void test5_f() {
+ extern int test5_b; // expected-note {{declared with C language linkage here}}
+ }
}
}
extern "C" {
@@ -46,6 +57,15 @@ extern "C" {
}
extern "C" {
+ void test5c_f() {
+ extern int test5_c; // expected-note {{previous}}
+ }
+}
+extern "C" {
+ static float test5_c; // expected-error {{redefinition of 'test5_c' with a different type: 'float' vs 'int'}}
+}
+
+extern "C" {
void f() {
extern int test6_b;
}
Modified: cfe/trunk/test/SemaCXX/function-redecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/function-redecl.cpp?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/function-redecl.cpp (original)
+++ cfe/trunk/test/SemaCXX/function-redecl.cpp Thu Sep 19 20:15:31 2013
@@ -4,17 +4,14 @@ int foo(int);
namespace N {
void f1() {
void foo(int); // okay
- void bar(int);
+ void bar(int); // expected-note 2{{previous declaration is here}}
}
void foo(int); // expected-note 2{{previous declaration is here}}
void f2() {
int foo(int); // expected-error {{functions that differ only in their return type cannot be overloaded}}
- // FIXME: We should be able to diagnose the conflict between this
- // declaration of 'bar' and the previous one, even though they come
- // from different lexical scopes.
- int bar(int); // expected-note {{previous declaration is here}}
+ int bar(int); // expected-error {{functions that differ only in their return type cannot be overloaded}}
int baz(int); // expected-note {{previous declaration is here}}
{
Modified: cfe/trunk/test/SemaCXX/warn-unreachable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-unreachable.cpp?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-unreachable.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-unreachable.cpp Thu Sep 19 20:15:31 2013
@@ -62,8 +62,8 @@ void test5() {
struct S {
int mem;
} s;
- S &foor() __attribute__((noreturn));
- foor()
+ S &foonr() __attribute__((noreturn));
+ foonr()
.mem; // expected-warning {{will never be executed}}
}
Modified: cfe/trunk/www/cxx_dr_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=191064&r1=191063&r2=191064&view=diff
==============================================================================
--- cfe/trunk/www/cxx_dr_status.html (original)
+++ cfe/trunk/www/cxx_dr_status.html Thu Sep 19 20:15:31 2013
@@ -212,7 +212,7 @@
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#29">29</a></td>
<td>CD1</td>
<td>Linkage of locally declared functions</td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#30">30</a></td>
More information about the cfe-commits
mailing list