Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -4007,9 +4007,11 @@ // odr-use cannot be determined from the current context (for instance, // because the name denotes a virtual function and was written without an // explicit nested-name-specifier). - void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool MightBeOdrUse); + void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool MightBeOdrUse, + Expr *RefExpr = nullptr); void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, - bool MightBeOdrUse = true); + bool MightBeOdrUse = true, + Expr *RefExpr = nullptr); void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var); void MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base = nullptr); void MarkMemberReferenced(MemberExpr *E); @@ -10667,6 +10669,14 @@ CharUnits Alignment); public: + /// \brief Mark the declaration used, in the sense of odr-use. + /// + /// This notifies any mutation listeners in addition to setting a bit + /// indicating the declaration is used. It traverse its associated types + /// and mark them as used. Intended mainly for debug information. + void markAllUsed(Decl *D, ASTContext &C, Expr *RefExpr = nullptr); + +public: /// \brief Diagnoses the current set of gathered accesses. This typically /// happens at full expression level. The set is cleared after emitting the /// diagnostics. Index: include/clang/Sema/SemaInternal.h =================================================================== --- include/clang/Sema/SemaInternal.h +++ include/clang/Sema/SemaInternal.h @@ -69,7 +69,7 @@ // *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack. inline void MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef, - const unsigned *const FunctionScopeIndexToStopAt) { + const unsigned *const FunctionScopeIndexToStopAt, Expr *RefExpr = nullptr) { // Keep track of used but undefined variables. // FIXME: We shouldn't suppress this warning for static data members. if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly && @@ -87,7 +87,7 @@ CaptureType, DeclRefType, FunctionScopeIndexToStopAt); - Var->markUsed(SemaRef.Context); + SemaRef.markAllUsed(Var, SemaRef.Context, RefExpr); } /// Return a DLL attribute from the declaration. Index: lib/AST/ASTDumper.cpp =================================================================== --- lib/AST/ASTDumper.cpp +++ lib/AST/ASTDumper.cpp @@ -1991,6 +1991,7 @@ void ASTDumper::VisitLabelStmt(const LabelStmt *Node) { VisitStmt(Node); OS << " '" << Node->getName() << "'"; + dumpDecl(Node->getDecl()); } void ASTDumper::VisitGotoStmt(const GotoStmt *Node) { Index: lib/AST/DeclBase.cpp =================================================================== --- lib/AST/DeclBase.cpp +++ lib/AST/DeclBase.cpp @@ -410,9 +410,7 @@ } void Decl::markUsed(ASTContext &C) { - if (isUsed(false)) - return; - + // The 'markAllUsed' does the check for an already used declaration. if (C.getASTMutationListener()) C.getASTMutationListener()->DeclarationMarkedUsed(this); Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -20,6 +20,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyDeclStackTrace.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtCXX.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/PartialDiagnostic.h" @@ -1869,3 +1870,641 @@ return checkOpenCLDisabledTypeOrDecl(&D, E.getLocStart(), FnName, OpenCLDeclExtMap, 1, D.getSourceRange()); } + +// Visitor to set the 'used' bit. +class UsedSetter : public RecursiveASTVisitor { +using VisitorBase = RecursiveASTVisitor; +public: + UsedSetter(Sema *S, ASTContext &C, Expr *RefExpr) : + S(S), C(C), CurContext(S->CurContext), RefExpr(RefExpr) {} + +public: + // C Types. + bool VisitArrayType(const ArrayType *T); + bool VisitAtomicType(const AtomicType *T); + bool VisitBlockPointerType(const BlockPointerType *T); + bool VisitEnumType(const EnumType *T); + bool VisitIncompleteArrayType(const IncompleteArrayType *T); + bool VisitParenType(const ParenType *T); + bool VisitPointerType(const PointerType *T); + bool VisitTypedefType(const TypedefType *T); + bool VisitVariableArrayType(const VariableArrayType *T); + + // C++ Types. + bool VisitAttributedType(const AttributedType *T); + bool VisitComplexType(const ComplexType *T); + bool VisitConstantArrayType(const ConstantArrayType *T); + bool VisitDecayedType(const DecayedType *T); + bool VisitDecltypeType(const DecltypeType *T); + bool VisitDependentSizedArrayType(const DependentSizedArrayType *T); + bool VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *T); + bool VisitElaboratedType(const ElaboratedType *T); + bool VisitExtVectorType(const ExtVectorType *T); + bool VisitLValueReferenceType(const LValueReferenceType *T); + bool VisitMemberPointerType(const MemberPointerType *T); + bool VisitRecordType(const RecordType *T); + bool VisitReferenceType(const ReferenceType *T); + bool VisitRValueReferenceType(const RValueReferenceType *T); + bool VisitTypeOfType(const TypeOfType *T); + bool VisitUnaryTransformType(const UnaryTransformType *T); + bool VisitUnresolvedUsingType(const UnresolvedUsingType *T); + bool VisitVectorType(const VectorType *T); + + // ObjC Types. + bool VisitObjCInterfaceType(const ObjCInterfaceType *T); + bool VisitObjCObjectPointerType(const ObjCObjectPointerType *T); + bool VisitObjCObjectType(const ObjCObjectType *T); + + // C Decls. + bool VisitBlockDecl(const BlockDecl *D); + bool VisitDeclContext(DeclContext *DC); + bool VisitEnumConstantDecl(EnumConstantDecl *D); + bool VisitEnumDecl(EnumDecl *D); + bool VisitFieldDecl(FieldDecl *D); + bool VisitFunctionDecl(FunctionDecl *D); + bool VisitLabelDecl(LabelDecl *D); + bool VisitParmVarDecl(ParmVarDecl *D); + bool VisitRecordDecl(RecordDecl *D); + bool VisitTypedefDecl(TypedefNameDecl *D); + bool VisitVarDecl(VarDecl *D); + + // C++ Decls. + bool VisitCXXConstructorDecl(CXXConstructorDecl *D); + bool VisitCXXConversionDecl(CXXConversionDecl *D); + bool VisitCXXDestructorDecl(CXXDestructorDecl *D); + bool VisitCXXMethodDecl(CXXMethodDecl *D); + bool VisitCXXRecordDecl(CXXRecordDecl *D); + bool VisitNamespaceAliasDecl(NamespaceAliasDecl *D); + bool VisitNamespaceDecl(NamespaceDecl *D); + bool VisitTypeAliasDecl(TypeAliasDecl *D); + bool VisitUsingDecl(UsingDecl *D); + bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + bool VisitUsingShadowDecl(UsingShadowDecl *D); + + // OpenMP Decls. + bool VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D); + bool VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D); + bool VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + + // ObjC Decls. + bool VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); + bool VisitObjCCategoryDecl(ObjCCategoryDecl *D); + bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); + bool VisitObjCImplementationDecl(ObjCImplementationDecl *D); + bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); + bool VisitObjCMethodDecl(ObjCMethodDecl *D); + bool VisitObjCPropertyDecl(ObjCPropertyDecl *D); + bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); + bool VisitObjCProtocolDecl(ObjCProtocolDecl *D); + +public: + bool VisitDecl(Decl *D); + +private: + // Mark usings dependencies. + void markSymbolFromNamespace(NamedDecl *D); + void markUsings(Decl *D, QualType T); + bool markUsings(DeclContext *LookupContext, NamedDecl *TargetDecl, + NamespaceDecl *TargetNamespace); + + // Mark parent context for given declaration. + void markParentContext(Decl *D); + +private: + Sema *S; + ASTContext &C; + DeclContext *CurContext; + Expr *RefExpr; +}; + +//===---------------------------------------------------------------------===// +// C Types. +//===---------------------------------------------------------------------===// +bool UsedSetter::VisitArrayType(const ArrayType *T) { + return TraverseType(T->getElementType()); +} +bool UsedSetter::VisitAtomicType(const AtomicType *T) { + return TraverseType(T->getValueType()); +} +bool UsedSetter::VisitBlockPointerType(const BlockPointerType *T) { + return TraverseType(T->getPointeeType()); +} +bool UsedSetter::VisitEnumType(const EnumType *T) { + return VisitEnumDecl(T->getDecl()); +} +bool UsedSetter::VisitIncompleteArrayType(const IncompleteArrayType *T) { + return VisitArrayType(T); +} +bool UsedSetter::VisitParenType(const ParenType *T) { + return TraverseType(T->getInnerType()); +} +bool UsedSetter::VisitPointerType(const PointerType *T) { + return TraverseType(T->getPointeeType()); +} +bool UsedSetter::VisitTypedefType(const TypedefType *T) { + return VisitTypedefDecl(T->getDecl()); +} +bool UsedSetter::VisitVariableArrayType(const VariableArrayType *T) { + return VisitArrayType(T); +} + +//===---------------------------------------------------------------------===// +// C++ Types. +//===---------------------------------------------------------------------===// +bool UsedSetter::VisitAttributedType(const AttributedType *T) { + return TraverseType(T->getModifiedType()); +} +bool UsedSetter::VisitComplexType(const ComplexType *T) { + return TraverseType(T->getElementType()); +} +bool UsedSetter::VisitConstantArrayType(const ConstantArrayType *T) { + return VisitArrayType(T); +} +bool UsedSetter::VisitDecayedType(const DecayedType *T) { + return TraverseType(T->getPointeeType()); +} +bool UsedSetter::VisitDecltypeType(const DecltypeType *T) { + return TraverseType(T->getUnderlyingType()); +} +bool UsedSetter::VisitDependentSizedArrayType( + const DependentSizedArrayType *T) { + return VisitArrayType(T); +} +bool UsedSetter::VisitDependentSizedExtVectorType( + const DependentSizedExtVectorType *T) { + return TraverseType(T->getElementType()); +} +bool UsedSetter::VisitElaboratedType(const ElaboratedType *T) { + return TraverseType(T->getNamedType()); +} +bool UsedSetter::VisitExtVectorType(const ExtVectorType *T) { + return VisitVectorType(T); +} +bool UsedSetter::VisitLValueReferenceType(const LValueReferenceType *T) { + return VisitReferenceType(T); +} +bool UsedSetter::VisitMemberPointerType(const MemberPointerType *T) { + return TraverseType(T->getPointeeType()); +} +bool UsedSetter::VisitRecordType(const RecordType *T) { + return VisitRecordDecl(T->getDecl()); +} +bool UsedSetter::VisitReferenceType(const ReferenceType *T) { + return TraverseType(T->getPointeeType()); +} +bool UsedSetter::VisitRValueReferenceType(const RValueReferenceType *T) { + return VisitReferenceType(T); +} +bool UsedSetter::VisitTypeOfType(const TypeOfType *T) { + return TraverseType(T->getUnderlyingType()); +} +bool UsedSetter::VisitUnaryTransformType(const UnaryTransformType *T) { + return TraverseType(T->getUnderlyingType()); +} +bool UsedSetter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) { + return VisitUnresolvedUsingTypenameDecl(T->getDecl()); +} +bool UsedSetter::VisitVectorType(const VectorType *T) { + return TraverseType(T->getElementType()); +} + +//===---------------------------------------------------------------------===// +// ObjC Types. +//===---------------------------------------------------------------------===// +bool UsedSetter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { + return true; +} +bool UsedSetter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { + return true; +} +bool UsedSetter::VisitObjCObjectType(const ObjCObjectType *T) { + return true; +} + +//===---------------------------------------------------------------------===// +// C Decls. +//===---------------------------------------------------------------------===// +bool UsedSetter::VisitBlockDecl(const BlockDecl *D) { + return true; +} +bool UsedSetter::VisitDeclContext(DeclContext *DC) { + // Base: CXXMethodDecl + if (auto *CD = dyn_cast(DC)) + return VisitCXXConstructorDecl(CD); + + // Base: CXXMethodDecl + if (auto *DD = dyn_cast(DC)) + return VisitCXXDestructorDecl(DD); + + // Base: CXXMethodDecl + if (auto *CD = dyn_cast(DC)) + return VisitCXXConversionDecl(CD); + + // Base: FunctionDecl + if (auto *MD = dyn_cast(DC)) + return VisitCXXMethodDecl(MD); + + // Base: DeclaratorDecl + if (auto *FD = dyn_cast(DC)) + return VisitFunctionDecl(FD); + + // Base: NamedDecl + if (auto *ND = dyn_cast(DC)) + return VisitNamespaceDecl(ND); + + // Base: TagDecl + if (auto *RD = dyn_cast(DC)) + return VisitRecordDecl(RD); + + // Base: Decl + if (auto *BD = dyn_cast(DC)) + return VisitBlockDecl(BD); + + return true; +} +bool UsedSetter::VisitEnumConstantDecl(EnumConstantDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + return TraverseType(D->getType()); +} +bool UsedSetter::VisitEnumDecl(EnumDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + return TraverseType(D->getPromotionType()); +} +bool UsedSetter::VisitFieldDecl(FieldDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + // Mark the field type. + auto T = D->getType(); + markUsings(D, T); + return TraverseType(T); +} +bool UsedSetter::VisitFunctionDecl(FunctionDecl *D) { + if (D->isUsed(false) && !RefExpr) + return true; + D->markUsed(C); + + markParentContext(D); + + // Mark parameters. + if (D->getNumParams()) + for (auto *PD : D->parameters()) + VisitParmVarDecl(PD); + + // Mark return type. + auto T = D->getReturnType(); + markUsings(D, T); + + // Check if the symbols referenced by a 'using' statement. + markSymbolFromNamespace(D); + + return TraverseType(T); +} +bool UsedSetter::VisitLabelDecl(LabelDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + return VisitDeclContext(D->getDeclContext()); +} +bool UsedSetter::VisitParmVarDecl(ParmVarDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + // Mark the parameter type. + auto T = D->getType(); + markUsings(D, T); + return TraverseType(T); +} +bool UsedSetter::VisitRecordDecl(RecordDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + // Mark non-static fields. + for (auto *FD : D->fields()) + VisitFieldDecl(FD); + + markParentContext(D); + return true; +} +bool UsedSetter::VisitTypedefDecl(TypedefNameDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + markParentContext(D); + return TraverseType(D->getUnderlyingType()); +} +bool UsedSetter::VisitVarDecl(VarDecl *D) { + if (D->isUsed(false) && !RefExpr) + return true; + D->markUsed(C); + + markParentContext(D); + + // Mark the variable type. + auto T = D->getType(); + markUsings(D, T); + + // Check if the symbols referenced by a 'using' statement. + markSymbolFromNamespace(D); + + return TraverseType(T); +} + +//===---------------------------------------------------------------------===// +// C++ Decls. +//===---------------------------------------------------------------------===// +bool UsedSetter::VisitCXXConstructorDecl(CXXConstructorDecl *D) { + return VisitCXXMethodDecl(D); +} +bool UsedSetter::VisitCXXConversionDecl(CXXConversionDecl *D) { + return VisitCXXMethodDecl(D); +} +bool UsedSetter::VisitCXXDestructorDecl(CXXDestructorDecl *D) { + return VisitCXXMethodDecl(D); +} +bool UsedSetter::VisitCXXMethodDecl(CXXMethodDecl *D) { + return VisitFunctionDecl(D); +} +bool UsedSetter::VisitCXXRecordDecl(CXXRecordDecl *D) { + return VisitRecordDecl(D); +} +bool UsedSetter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + return VisitNamespaceDecl(D->getNamespace()); +} +bool UsedSetter::VisitNamespaceDecl(NamespaceDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + markParentContext(D); + return true; +} +bool UsedSetter::VisitTypeAliasDecl(TypeAliasDecl *D) { + if (D->isUsed(false)) + return true; + + return TraverseType(D->getUnderlyingType()); +} +bool UsedSetter::VisitUsingDecl(UsingDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + return true; +} +bool UsedSetter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + return VisitNamespaceDecl(D->getNominatedNamespace()); +} +bool UsedSetter::VisitUsingShadowDecl(UsingShadowDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + // Mark the associated using declaration. + return VisitUsingDecl(D->getUsingDecl()); +} + +//===---------------------------------------------------------------------===// +// OpenMP Decls. +//===---------------------------------------------------------------------===// +bool UsedSetter::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) { + return true; +} +bool UsedSetter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { + return true; +} +bool UsedSetter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { + return true; +} + +//===---------------------------------------------------------------------===// +// ObjC Decls. +//===---------------------------------------------------------------------===// +bool UsedSetter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { + return true; +} +bool UsedSetter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + return true; +} +bool UsedSetter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) { + return true; +} +bool UsedSetter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { + return true; +} +bool UsedSetter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { + return true; +} +bool UsedSetter::VisitObjCMethodDecl(ObjCMethodDecl *D) { + return true; +} +bool UsedSetter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { + return true; +} +bool UsedSetter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { + return true; +} +bool UsedSetter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { + return true; +} + +/// \brief For the given declaration, mark all its parent context as used. +void UsedSetter::markParentContext(Decl *D) { + // For the given declaration, mark its parent context. + for (auto *DC = D->getDeclContext(); + !isa(DC) && + !isa(DC) && D->isUsed(false); DC = DC->getParent()) + VisitDeclContext(DC); +} + +/// \brief For the given declaration (variable or function), mark as used +/// any associated 'using' statement. +void UsedSetter::markSymbolFromNamespace(NamedDecl *D) { + // For a function or variable declared in a namespace, check for 'using' + // statement. Use the context passed by Sema, as it corresponds to the + // context where the variable or function is being referenced. + auto *DC = D->getDeclContext(); + if (DC->isNamespace()) { + // Check if the referenced variable or function contains any named + // qualifiers. As this function can be called recursively, ignore + // the calls that do not refer to the original referenced variable + // or function. + DeclRefExpr *DRE; + if (RefExpr && (DRE = dyn_cast(RefExpr))) { + auto *VD = cast(DRE->getDecl()); + if (VD == D && !DRE->hasQualifier()) + if (markUsings(CurContext, D, dyn_cast(DC))) + return; + } + // Consider namespace aliases. + auto *TargetNamespace = dyn_cast(DC); + for (DC = CurContext; DC; DC = DC->getParent()) { + for (auto *DR : DC->decls()) + if (auto *NA = dyn_cast(DR)) { + if (NA->getNamespace() == TargetNamespace) { + VisitNamespaceAliasDecl(NA); + return; + } + } + } + } +} + +/// \brief If the given type was introduced by a 'using' statement, mark its +// associated 'using' as used. +void UsedSetter::markUsings(Decl *D, QualType QT) { + // In the case of name qualified type, do not look for any reference to + // a 'using' declaration. + // namespace N { + // typedef int INT; + // } + // void foo { + // N::INT var; + // } + if (isa(QT)) + return; + + NamedDecl *TargetDecl = nullptr; + auto *T = QT.getTypePtr(); + if (auto *TT = dyn_cast(T)) + TargetDecl = TT->getDecl(); + else if (auto *RT = dyn_cast(T)) + TargetDecl = RT->getDecl(); + + if (TargetDecl) { + // To have a proper search on 'using' statements, we need to determine + // the correct lookup context, based on the symbol being marked as used. + // In the case of parameters, the lookup context is the enclosing scope. + auto *LookupContext = D->getDeclContext(); + if (D->getKind() == Decl::ParmVar) + LookupContext = LookupContext->getParent(); + + auto *DC = TargetDecl->getDeclContext(); + if (DC->isNamespace()) + markUsings(LookupContext, TargetDecl, dyn_cast(DC)); + } +} + +/// \brief If the given declaration was introduced by a 'using' statement, +// mark its associated 'using' as used. +bool UsedSetter::markUsings(DeclContext *LookupContext, NamedDecl *TargetDecl, + NamespaceDecl *TargetNamespace) { + // Look for an introduced declaration via a 'using' statement. + // Do not perform lookups into transparent contexts. + for (auto *DC = LookupContext; + DC && !isa(DC) && !isa(DC); + DC = DC->getParent()) { + // The using-declaration are contained in the returned 'decls()'. + for (auto *DR : DC->decls()) + if (auto *USD = dyn_cast(DR)) { + if (USD->getTargetDecl() == TargetDecl) { + VisitUsingShadowDecl(USD); + return true; + } + } + // Check for using-directives. + for (auto *UD : DC->using_directives()) + if (UD->getNominatedNamespace() == TargetNamespace) { + VisitUsingDirectiveDecl(UD); + return true; + } + } + + // Do not perform lookups into transparent contexts. + if (LookupContext->getDeclKind() == Decl::LinkageSpec || + LookupContext->getDeclKind() == Decl::Export) + return false; + + if (auto *scope = S->getScopeForContext(LookupContext)) + for (auto *UD : scope->using_directives()) + if (UD->getNominatedNamespace() == TargetNamespace) { + VisitUsingDirectiveDecl(UD); + return true; + } + + return false; +} + +bool UsedSetter::VisitDecl(Decl *D) { + // This is the main entry point to mark the given declaration as used. + // We deal only with functions and variables. + + // Base: CXXMethodDecl + if (auto *CD = dyn_cast(D)) + return VisitCXXConstructorDecl(CD); + + // Base: CXXMethodDecl + if (auto *DD = dyn_cast(D)) + return VisitCXXDestructorDecl(DD); + + // Base: CXXMethodDecl + if (auto *CD = dyn_cast(D)) + return VisitCXXConversionDecl(CD); + + // Base: FunctionDecl + if (auto *MD = dyn_cast(D)) + return VisitCXXMethodDecl(MD); + + // Base: DeclaratorDecl + if (auto *FD = dyn_cast(D)) + return VisitFunctionDecl(FD); + + // Base: VarDecl + if (auto *PD = dyn_cast(D)) + return VisitParmVarDecl(PD); + + // Base: DeclaratorDecl + if (auto *VD = dyn_cast(D)) + return VisitVarDecl(VD); + + // Base: NamedDecl + if (auto *LD = dyn_cast(D)) + return VisitLabelDecl(LD); + + // For unsupported ObjC or OpenMP declarations. + D->markUsed(C); + return true; +} + +void Sema::markAllUsed(Decl *D, ASTContext &C, Expr *RefExpr) { + // When setting the 'used' bit for referenced variables or functions, the + // 'RefExpr' is the expression associated with that reference. Within the + // same context, the variable or function can be referenced more than once: + // namespace M { void Foo(); } + // namespace N { int a; } + // void Bar() { + // M::Foo(); <-- Marked as used. RefExpr1; + // using M::Foo; + // Foo(); <-- Already marked as used. RefExpr2; + // <-- We have to mark the 'using' statement. + // + // N::a = 1; <-- Marked as used. RefExpr3; + // using N::a; + // a = 2; <-- Already marked as used. RefExpr4; + // <-- We have to mark the 'using' statement. + // } + if (D->isUsed(false) && !RefExpr) + return; + + UsedSetter Setter(this, C, RefExpr); + Setter.VisitDecl(D); +} Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -10717,7 +10717,7 @@ ? Constructor->getLocEnd() : Constructor->getLocation(); Constructor->setBody(new (Context) CompoundStmt(Loc)); - Constructor->markUsed(Context); + markAllUsed(Constructor, Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Constructor); @@ -10893,7 +10893,7 @@ } Constructor->setBody(new (Context) CompoundStmt(InitLoc)); - Constructor->markUsed(Context); + markAllUsed(Constructor, Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Constructor); @@ -11000,7 +11000,7 @@ ? Destructor->getLocEnd() : Destructor->getLocation(); Destructor->setBody(new (Context) CompoundStmt(Loc)); - Destructor->markUsed(Context); + markAllUsed(Destructor, Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Destructor); @@ -11809,7 +11809,7 @@ assert(!Body.isInvalid() && "Compound statement creation cannot fail"); } CopyAssignOperator->setBody(Body.getAs()); - CopyAssignOperator->markUsed(Context); + markAllUsed(CopyAssignOperator, Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(CopyAssignOperator); @@ -12180,7 +12180,7 @@ assert(!Body.isInvalid() && "Compound statement creation cannot fail"); } MoveAssignOperator->setBody(Body.getAs()); - MoveAssignOperator->markUsed(Context); + markAllUsed(MoveAssignOperator, Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(MoveAssignOperator); @@ -12315,7 +12315,7 @@ Sema::CompoundScopeRAII CompoundScope(*this); CopyConstructor->setBody( ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs()); - CopyConstructor->markUsed(Context); + markAllUsed(CopyConstructor, Context); } if (ASTMutationListener *L = getASTMutationListener()) { @@ -12438,7 +12438,7 @@ Sema::CompoundScopeRAII CompoundScope(*this); MoveConstructor->setBody(ActOnCompoundStmt( Loc, Loc, None, /*isStmtExpr=*/ false).getAs()); - MoveConstructor->markUsed(Context); + markAllUsed(MoveConstructor, Context); } if (ASTMutationListener *L = getASTMutationListener()) { @@ -12485,7 +12485,7 @@ // Fill in the __invoke function with a dummy implementation. IR generation // will fill in the actual details. Update its type in case it contained // an 'auto'. - Invoker->markUsed(Context); + markAllUsed(Invoker, Context); Invoker->setReferenced(); Invoker->setType(Conv->getReturnType()->getPointeeType()); Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation())); @@ -12497,7 +12497,7 @@ Stmt *Return = BuildReturnStmt(Conv->getLocation(), FunctionRef).get(); Conv->setBody(CompoundStmt::Create(Context, Return, Conv->getLocation(), Conv->getLocation())); - Conv->markUsed(Context); + markAllUsed(Conv, Context); Conv->setReferenced(); if (ASTMutationListener *L = getASTMutationListener()) { @@ -12552,7 +12552,7 @@ Stmt *ReturnS = Return.get(); Conv->setBody(CompoundStmt::Create(Context, ReturnS, Conv->getLocation(), Conv->getLocation())); - Conv->markUsed(Context); + markAllUsed(Conv, Context); // We're done; notify the mutation listener, if any. if (ASTMutationListener *L = getASTMutationListener()) { Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -12569,7 +12569,7 @@ /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, LabelDecl *TheDecl) { - TheDecl->markUsed(Context); + markAllUsed(TheDecl, Context); // Create the AST node. The address of a label always has type 'void*'. return new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl, Context.getPointerType(Context.VoidTy)); @@ -13969,7 +13969,7 @@ /// \brief Mark a function referenced, and check whether it is odr-used /// (C++ [basic.def.odr]p2, C99 6.9p3) void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, - bool MightBeOdrUse) { + bool MightBeOdrUse, Expr *RefExpr) { assert(Func && "No function?"); Func->setReferenced(); @@ -14135,7 +14135,7 @@ UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc)); } - Func->markUsed(Context); + markAllUsed(Func, Context, RefExpr); } static void @@ -14491,7 +14491,7 @@ CopyExpr = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable, DeclRefType, VK_LValue, Loc); Var->setReferenced(true); - Var->markUsed(S.Context); + S.markAllUsed(Var, S.Context); } // Actually capture the variable. @@ -15024,7 +15024,7 @@ SemaRef.MaybeODRUseExprs.insert(E); } else if (OdrUseContext) { MarkVarDeclODRUsed(Var, Loc, SemaRef, - /*MaxFunctionScopeIndex ptr*/ nullptr); + /*MaxFunctionScopeIndex ptr*/ nullptr, E); } else if (isOdrUseContext(SemaRef, /*SkipDependentUses*/false)) { // If this is a dependent context, we don't need to mark variables as // odr-used, but we may still need to track them for lambda capture. @@ -15072,7 +15072,7 @@ return; } - SemaRef.MarkAnyDeclReferenced(Loc, D, MightBeOdrUse); + SemaRef.MarkAnyDeclReferenced(Loc, D, MightBeOdrUse, E); // If this is a call to a method via a cast, also mark the method in the // derived class used in case codegen can devirtualize the call. @@ -15093,7 +15093,7 @@ CXXMethodDecl *DM = MD->getDevirtualizedMethod( ME->getBase(), SemaRef.getLangOpts().AppleKext); if (DM) - SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse); + SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse, E); } /// \brief Perform reference-marking and odr-use handling for a DeclRefExpr. @@ -15133,7 +15133,7 @@ /// functions and variables. This method should not be used when building a /// normal expression which refers to a variable. void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, - bool MightBeOdrUse) { + bool MightBeOdrUse, Expr *RefExpr) { if (MightBeOdrUse) { if (auto *VD = dyn_cast(D)) { MarkVariableReferenced(Loc, VD); @@ -15141,7 +15141,7 @@ } } if (auto *FD = dyn_cast(D)) { - MarkFunctionReferenced(Loc, FD, MightBeOdrUse); + MarkFunctionReferenced(Loc, FD, MightBeOdrUse, RefExpr); return; } D->setReferenced(); Index: lib/Sema/SemaLambda.cpp =================================================================== --- lib/Sema/SemaLambda.cpp +++ lib/Sema/SemaLambda.cpp @@ -802,7 +802,7 @@ NewVD->setReferenced(true); // FIXME: Pass in a VarDecl::InitializationStyle. NewVD->setInitStyle(static_cast(InitStyle)); - NewVD->markUsed(Context); + markAllUsed(NewVD, Context); NewVD->setInit(Init); return NewVD; } @@ -1665,7 +1665,7 @@ Lambda->lookup( Context.DeclarationNames.getCXXOperatorName(OO_Call)).front()); CallOperator->setReferenced(); - CallOperator->markUsed(Context); + markAllUsed(CallOperator, Context); ExprResult Init = PerformCopyInitialization( InitializedEntity::InitializeLambdaToBlock(ConvLocation, Src->getType(), Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -848,7 +848,7 @@ SourceLocation Loc, bool RefersToCapture = false) { D->setReferenced(); - D->markUsed(S.Context); + S.markAllUsed(D, S.Context); return DeclRefExpr::Create(S.getASTContext(), NestedNameSpecifierLoc(), SourceLocation(), D, RefersToCapture, Loc, Ty, VK_LValue); @@ -1811,7 +1811,7 @@ // Mark variable as used. VD->setReferenced(); - VD->markUsed(Context); + markAllUsed(VD, Context); QualType QType = VD->getType(); if (QType->isDependentType() || QType->isInstantiationDependentType()) { Index: lib/Sema/SemaStmt.cpp =================================================================== --- lib/Sema/SemaStmt.cpp +++ lib/Sema/SemaStmt.cpp @@ -2306,7 +2306,7 @@ if (RangeVarType->isDependentType()) { // The range is implicitly used as a placeholder when it is dependent. - RangeVar->markUsed(Context); + markAllUsed(RangeVar, Context); // Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill // them in properly when we instantiate the loop. @@ -2785,7 +2785,7 @@ SourceLocation LabelLoc, LabelDecl *TheDecl) { setFunctionHasBranchIntoScope(); - TheDecl->markUsed(Context); + markAllUsed(TheDecl, Context); return new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc); } Index: lib/Sema/SemaStmtAsm.cpp =================================================================== --- lib/Sema/SemaStmtAsm.cpp +++ lib/Sema/SemaStmtAsm.cpp @@ -810,7 +810,7 @@ if (Label->isMSAsmLabel()) { // If we have previously created this label implicitly, mark it as used. - Label->markUsed(Context); + markAllUsed(Label, Context); } else { // Otherwise, insert it, but only resolve it if we have seen the label itself. std::string InternalName; Index: test/Frontend/float16.cpp =================================================================== --- test/Frontend/float16.cpp +++ test/Frontend/float16.cpp @@ -110,9 +110,9 @@ } }; -//CHECK: |-CXXRecordDecl {{.*}} referenced class C1 definition +//CHECK: |-CXXRecordDecl {{.*}} used class C1 definition //CHECK: | |-CXXRecordDecl {{.*}} implicit referenced class C1 -//CHECK-NEXT: | |-FieldDecl {{.*}} referenced f1c '_Float16' +//CHECK-NEXT: | |-FieldDecl {{.*}} used f1c '_Float16' //CHECK-NEXT: | |-VarDecl {{.*}} used f2c 'const _Float16' static //CHECK-NEXT: | |-FieldDecl {{.*}} f3c 'volatile _Float16' //CHECK-NEXT: | |-AccessSpecDecl Index: test/Misc/ast-dump-attr.cpp =================================================================== --- test/Misc/ast-dump-attr.cpp +++ test/Misc/ast-dump-attr.cpp @@ -95,12 +95,14 @@ // CHECK-NEXT: UnusedAttr{{.*}} M: __attribute(()) int j; -// CHECK: LabelStmt {{.*}} 'M' +// CHECK: LabelStmt {{.*}} 'M' +// CHECK-NEXT: LabelDecl // CHECK-NEXT: DeclStmt // CHECK-NEXT: VarDecl {{.*}} j 'int' N: __attribute(()) ; // CHECK: LabelStmt {{.*}} 'N' +// CHECK-NEXT: LabelDecl // CHECK-NEXT: NullStmt } Index: test/Misc/ast-dump-color.cpp =================================================================== --- test/Misc/ast-dump-color.cpp +++ test/Misc/ast-dump-color.cpp @@ -62,14 +62,14 @@ //CHECK: {{^}}[[Blue]]| `-[[RESET]][[Blue]]FullComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:8:4[[RESET]], [[Yellow]]col:11[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| `-[[RESET]][[Blue]]ParagraphComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:4[[RESET]], [[Yellow]]col:11[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| `-[[RESET]][[Blue]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:4[[RESET]], [[Yellow]]col:11[[RESET]]> Text=" Comment"{{$}} -//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:18:1[[RESET]], [[Yellow]]line:25:1[[RESET]]> [[Yellow]]line:18:33[[RESET]] class[[CYAN]] Mutex[[RESET]] definition{{$}} +//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:18:1[[RESET]], [[Yellow]]line:25:1[[RESET]]> [[Yellow]]line:18:33[[RESET]] used class[[CYAN]] Mutex[[RESET]] definition{{$}} //CHECK: {{^}}[[Blue]]| |-[[RESET]][[BLUE]]CapabilityAttr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:22[[RESET]]> capability "mutex"{{$}} //CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:1[[RESET]], [[Yellow]]col:33[[RESET]]> [[Yellow]]col:33[[RESET]] implicit class[[CYAN]] Mutex[[RESET]]{{$}} -//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]FieldDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:20:3[[RESET]], [[Yellow]]col:7[[RESET]]> [[Yellow]]col:7[[RESET]][[CYAN]] var1[[RESET]] [[Green]]'int'[[RESET]]{{$}} +//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]FieldDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:20:3[[RESET]], [[Yellow]]col:7[[RESET]]> [[Yellow]]col:7[[RESET]] used[[CYAN]] var1[[RESET]] [[Green]]'int'[[RESET]]{{$}} //CHECK: {{^}}[[Blue]]| | `-[[RESET]][[Blue]]FullComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:19:6[[RESET]], [[Yellow]]col:16[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| | `-[[RESET]][[Blue]]ParagraphComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:6[[RESET]], [[Yellow]]col:16[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| | `-[[RESET]][[Blue]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:6[[RESET]], [[Yellow]]col:16[[RESET]]> Text=" A variable"{{$}} -//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]FieldDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:24:3[[RESET]], [[Yellow]]col:7[[RESET]]> [[Yellow]]col:7[[RESET]][[CYAN]] var2[[RESET]] [[Green]]'int'[[RESET]]{{$}} +//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]FieldDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:24:3[[RESET]], [[Yellow]]col:7[[RESET]]> [[Yellow]]col:7[[RESET]] used[[CYAN]] var2[[RESET]] [[Green]]'int'[[RESET]]{{$}} //CHECK: {{^}}[[Blue]]| | `-[[RESET]][[Blue]]FullComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:21:6[[RESET]], [[Yellow]]line:23:44[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| | |-[[RESET]][[Blue]]ParagraphComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:21:6[[RESET]], [[Yellow]]col:22[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| | | `-[[RESET]][[Blue]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:6[[RESET]], [[Yellow]]col:22[[RESET]]> Text=" Another variable"{{$}} @@ -88,7 +88,7 @@ //CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]VarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:26:1[[RESET]], [[Yellow]]col:5[[RESET]]> [[Yellow]]col:5[[RESET]][[CYAN]] TestExpr[[RESET]] [[Green]]'int'[[RESET]] //CHECK: {{^}}[[Blue]]| `-[[RESET]][[BLUE]]GuardedByAttr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:29[[RESET]], [[Yellow]]col:43[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| `-[[RESET]][[MAGENTA]]DeclRefExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:40[[RESET]]> [[Green]]'class Mutex':'Mutex'[[RESET]][[Cyan]] lvalue[[RESET]][[Cyan]][[RESET]] [[GREEN]]Var[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]][[CYAN]] 'mu1'[[RESET]] [[Green]]'class Mutex':'Mutex'[[RESET]]{{$}} -//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:28:1[[RESET]], [[Yellow]]line:30:1[[RESET]]> [[Yellow]]line:28:8[[RESET]] struct[[CYAN]] Invalid[[RESET]] definition +//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:28:1[[RESET]], [[Yellow]]line:30:1[[RESET]]> [[Yellow]]line:28:8[[RESET]] used struct[[CYAN]] Invalid[[RESET]] definition //CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:1[[RESET]], [[Yellow]]col:8[[RESET]]> [[Yellow]]col:8[[RESET]] implicit referenced struct[[CYAN]] Invalid[[RESET]] //CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:29:3[[RESET]], [[Yellow]]col:42[[RESET]]> [[Yellow]]col:29[[RESET]] invalid[[CYAN]] Invalid[[RESET]] [[Green]]'void (int)'[[RESET]] //CHECK: {{^}}[[Blue]]| | |-[[RESET]][[GREEN]]ParmVarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:37[[RESET]], [[Yellow]][[RESET]]> [[Yellow]]col:42[[RESET]] invalid [[Green]]'int'[[RESET]] Index: test/PCH/cxx-templates.cpp =================================================================== --- test/PCH/cxx-templates.cpp +++ test/PCH/cxx-templates.cpp @@ -5,12 +5,12 @@ // Test with pch. // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t -verify %s -ast-dump -o - -// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - -DNO_ERRORS | FileCheck %s // Test with modules. // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -x c++-header -emit-pch -o %t %S/cxx-templates.h // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t -verify %s -ast-dump -o - -// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS -fmodules-ignore-macro=NO_ERRORS | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t %s -emit-llvm -o - -DNO_ERRORS -fmodules-ignore-macro=NO_ERRORS | FileCheck %s // Test with pch and delayed template parsing. // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h @@ -28,7 +28,7 @@ }; void test(const int (&a6)[17]) { - int x = templ_f(3); + int x = templ_f(3);; S::templ(); S::partial(); Index: test/SemaCXX/used_class_struct_union.cpp =================================================================== --- test/SemaCXX/used_class_struct_union.cpp +++ test/SemaCXX/used_class_struct_union.cpp @@ -0,0 +1,133 @@ +// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace + +struct S { + void SF(int param) { + int var; + var = 1; + } +}; + +//CHECK: |-CXXRecordDecl {{.*}} used struct S definition +//CHECK-NEXT: | |-DefinitionData {{.*}} +//CHECK-NEXT: | | |-DefaultConstructor {{.*}} +//CHECK-NEXT: | | |-CopyConstructor {{.*}} +//CHECK-NEXT: | | |-MoveConstructor {{.*}} +//CHECK-NEXT: | | |-CopyAssignment {{.*}} +//CHECK-NEXT: | | |-MoveAssignment {{.*}} +//CHECK-NEXT: | | `-Destructor {{.*}} +//CHECK-NEXT: | |-CXXRecordDecl {{.*}} implicit struct S +//CHECK-NEXT: | |-CXXMethodDecl {{.*}} used SF 'void (int)' +//CHECK-NEXT: | | |-ParmVarDecl {{.*}} used param 'int' +//CHECK-NEXT: | | `-CompoundStmt {{.*}} +//CHECK-NEXT: | | |-DeclStmt {{.*}} +//CHECK-NEXT: | | | `-VarDecl {{.*}} used var 'int' +//CHECK-NEXT: | | `-BinaryOperator {{.*}} +//CHECK-NEXT: | | |-DeclRefExpr {{.*}} 'var' 'int' +//CHECK-NEXT: | | `-IntegerLiteral {{.*}} +//CHECK-NEXT: | |-CXXConstructorDecl {{.*}} +//CHECK-NEXT: | | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-CXXConstructorDecl {{.*}} +//CHECK-NEXT: | | `-ParmVarDecl {{.*}} 'const S &' +//CHECK-NEXT: | `-CXXConstructorDecl {{.*}} +//CHECK-NEXT: | `-ParmVarDecl {{.*}} 'S &&' + +typedef int INTEGER; +typedef float FLOAT; + +//CHECK: |-TypedefDecl {{.*}} used INTEGER 'int' +//CHECK-NEXT: | `-BuiltinType {{.*}} +//CHECK-NEXT: |-TypedefDecl {{.*}} FLOAT 'float' +//CHECK-NEXT: | `-BuiltinType {{.*}} + +class C { + typedef float FLOAT; + typedef int INTEGER; + ::INTEGER i; + FLOAT f; +public: + C() : i(0), f(0.0) {} + C(::INTEGER pi) : i(pi), f(0.0) {} + C(::INTEGER pi,FLOAT pf) : i(pi), f(pf) {} + void CF() {} +}; + +//CHECK: |-CXXRecordDecl {{.*}} used class C definition +//CHECK-NEXT: |-DefinitionData {{.*}} +//CHECK-NEXT: | |-DefaultConstructor {{.*}} +//CHECK-NEXT: | |-CopyConstructor {{.*}} +//CHECK-NEXT: | |-MoveConstructor {{.*}} +//CHECK-NEXT: | |-CopyAssignment {{.*}} +//CHECK-NEXT: | |-MoveAssignment {{.*}} +//CHECK-NEXT: | `-Destructor {{.*}} +//CHECK-NEXT: |-CXXRecordDecl {{.*}} implicit referenced class C +//CHECK-NEXT: |-TypedefDecl {{.*}} used FLOAT 'float' +//CHECK-NEXT: | `-BuiltinType {{.*}} +//CHECK-NEXT: |-TypedefDecl {{.*}} INTEGER 'int' +//CHECK-NEXT: | `-BuiltinType {{.*}} +//CHECK-NEXT: |-FieldDecl {{.*}} used i '::INTEGER':'int' +//CHECK-NEXT: |-FieldDecl {{.*}} used f 'C::FLOAT':'float' +//CHECK-NEXT: |-AccessSpecDecl {{.*}} public +//CHECK-NEXT: |-CXXConstructorDecl {{.*}} used C 'void ()' +//CHECK-NEXT: | |-CXXCtorInitializer {{.*}} +//CHECK-NEXT: | | `-IntegerLiteral {{.*}} +//CHECK-NEXT: | |-CXXCtorInitializer {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-FloatingLiteral {{.*}} +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: |-CXXConstructorDecl {{.*}} used C 'void (::INTEGER)' +//CHECK-NEXT: | |-ParmVarDecl {{.*}} used pi '::INTEGER':'int' +//CHECK-NEXT: | |-CXXCtorInitializer {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'pi' '::INTEGER':'int' +//CHECK-NEXT: | |-CXXCtorInitializer {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-FloatingLiteral {{.*}} +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: |-CXXConstructorDecl {{.*}} used C 'void (::INTEGER, C::FLOAT)' +//CHECK-NEXT: | |-ParmVarDecl {{.*}} used pi '::INTEGER':'int' +//CHECK-NEXT: | |-ParmVarDecl {{.*}} used pf 'C::FLOAT':'float' +//CHECK-NEXT: | |-CXXCtorInitializer {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'pi' '::INTEGER':'int' +//CHECK-NEXT: | |-CXXCtorInitializer {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'pf' 'C::FLOAT':'float' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: |-CXXMethodDecl {{.*}} CF 'void ()' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: |-CXXConstructorDecl {{.*}} +//CHECK-NEXT: | `-ParmVarDecl {{.*}} 'const C &' +//CHECK-NEXT: `-CXXConstructorDecl {{.*}} +//CHECK-NEXT: `-ParmVarDecl {{.*}} 'C &&' + +void Foo() { + S r; + r.SF(1); + + C c1; + C c2(1); + C c3(1,1.1); +} + +//CHECK: `-FunctionDecl {{.*}} used Foo 'void ()' +//CHECK-NEXT: `-CompoundStmt {{.*}} +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} used r 'S' callinit +//CHECK-NEXT: | `-CXXConstructExpr {{.*}} 'S' 'void () noexcept' +//CHECK-NEXT: |-CXXMemberCallExpr {{.*}} +//CHECK-NEXT: | |-MemberExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'r' 'S' +//CHECK-NEXT: | `-IntegerLiteral{{.*}} +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} 'C' callinit +//CHECK-NEXT: | `-CXXConstructExpr {{.*}} 'C' 'void ()' +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} 'C' callinit +//CHECK-NEXT: | `-CXXConstructExpr {{.*}} 'C' 'void (::INTEGER)' +//CHECK-NEXT: | `-IntegerLiteral{{.*}} +//CHECK-NEXT: `-DeclStmt {{.*}} +//CHECK-NEXT: `-VarDecl {{.*}} 'C' callinit +//CHECK-NEXT: `-CXXConstructExpr {{.*}} 'C' 'void (::INTEGER, C::FLOAT)' +//CHECK-NEXT: |-IntegerLiteral {{.*}} +//CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'C::FLOAT':'float' +//CHECK-NEXT: `-FloatingLiteral {{.*}} Index: test/SemaCXX/used_enum.cpp =================================================================== --- test/SemaCXX/used_enum.cpp +++ test/SemaCXX/used_enum.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace + +enum NUMBER { + ONE = 1, + TWO = 2 +}; + +//CHECK: |-EnumDecl {{.*}} used NUMBER +//CHECK-NEXT: | |-EnumConstantDecl {{.*}} ONE 'NUMBER' +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-IntegerLiteral {{.*}} +//CHECK-NEXT: | `-EnumConstantDecl {{.*}} referenced TWO 'NUMBER' +//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | `-IntegerLiteral {{.*}} + +enum LETTER { + A = 'a', + B = 'b', + C = 'c' +}; + +//CHECK: |-EnumDecl {{.*}} referenced LETTER +//CHECK-NEXT: | |-EnumConstantDecl {{.*}} A 'LETTER' +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-CharacterLiteral {{.*}} +//CHECK-NEXT: | |-EnumConstantDecl {{.*}} 'LETTER' +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-CharacterLiteral {{.*}} +//CHECK-NEXT: | `-EnumConstantDecl {{.*}} C 'LETTER' +//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | `-CharacterLiteral {{.*}} + +void Foo() { + NUMBER n; + n = TWO; + LETTER l; +} + +//CHECK: `-FunctionDecl {{.*}} used Foo 'void ()' +//CHECK-NEXT: `-CompoundStmt {{.*}} +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} used n 'NUMBER' +//CHECK-NEXT: |-BinaryOperator {{.*}} +//CHECK-NEXT: | |-DeclRefExpr {{.*}} 'n' 'NUMBER' +//CHECK-NEXT: | `-DeclRefExpr {{.*}} 'TWO' 'NUMBER' +//CHECK-NEXT: `-DeclStmt {{.*}} +//CHECK-NEXT: `-VarDecl {{.*}} l 'LETTER' Index: test/SemaCXX/used_goto.cpp =================================================================== --- test/SemaCXX/used_goto.cpp +++ test/SemaCXX/used_goto.cpp @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace + +void Foo(int p) { +start: + int a; + typedef int INT; + if (p) { + goto end; + do { + } while (--p); + } + +end: + return; +} + +void Bar() { + Foo(2); +} + +//CHECK: |-FunctionDecl {{.*}} used Foo 'void (int)' +//CHECK-NEXT: | |-ParmVarDecl {{.*}} used p 'int' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-LabelStmt {{.*}} 'start' +//CHECK-NEXT: | | |-LabelDecl {{.*}} start +//CHECK-NEXT: | | `-DeclStmt {{.*}} +//CHECK-NEXT: | | `-VarDecl {{.*}} a 'int' +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-TypedefDecl {{.*}} INT 'int' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | |-IfStmt {{.*}} +//CHECK-NEXT: | | |-<<>> +//CHECK-NEXT: | | |-<<>> +//CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'p' 'int' +//CHECK-NEXT: | | |-CompoundStmt {{.*}} +//CHECK-NEXT: | | | |-GotoStmt {{.*}} 'end' {{.*}} +//CHECK-NEXT: | | | `-DoStmt {{.*}} +//CHECK-NEXT: | | | |-CompoundStmt {{.*}} +//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | | `-UnaryOperator {{.*}} +//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'p' 'int' +//CHECK-NEXT: | | `-<<>> +//CHECK-NEXT: | `-LabelStmt {{.*}} 'end' +//CHECK-NEXT: | |-LabelDecl {{.*}} used end +//CHECK-NEXT: | `-ReturnStmt {{.*}} +//CHECK: `-FunctionDecl {{.*}} Bar 'void ()' +//CHECK-NEXT: `-CompoundStmt {{.*}} +//CHECK-NEXT: `-CallExpr {{.*}} +//CHECK-NEXT: |-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | `-DeclRefExpr {{.*}} 'Foo' 'void (int)' +//CHECK-NEXT: `-IntegerLiteral {{.*}} Index: test/SemaCXX/used_pointer.cpp =================================================================== --- test/SemaCXX/used_pointer.cpp +++ test/SemaCXX/used_pointer.cpp @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace + +typedef int INTEGER; +typedef INTEGER INT; + +//CHECK: |-TypedefDecl {{.*}} used INTEGER 'int' +//CHECK-NEXT: | `-BuiltinType {{.*}} +//CHECK-NEXT: |-TypedefDecl {{.*}} used INT 'INTEGER':'int' +//CHECK-NEXT: | `-TypedefType {{.*}} +//CHECK-NEXT: | |-Typedef {{.*}} +//CHECK-NEXT: | `-BuiltinType {{.*}} + +struct S { + static int si; + INT fi; + void F() {} +}; + +//CHECK: |-CXXRecordDecl {{.*}} used struct S definition +//CHECK-NEXT: | |-DefinitionData {{.*}} +//CHECK-NEXT: | | |-DefaultConstructor {{.*}} +//CHECK-NEXT: | | |-CopyConstructor {{.*}} +//CHECK-NEXT: | | |-MoveConstructor {{.*}} +//CHECK-NEXT: | | |-CopyAssignment {{.*}} +//CHECK-NEXT: | | |-MoveAssignment {{.*}} +//CHECK-NEXT: | | `-Destructor {{.*}} +//CHECK-NEXT: | |-CXXRecordDecl {{.*}} implicit struct S +//CHECK-NEXT: | |-VarDecl {{.*}} used si 'int' static +//CHECK-NEXT: | |-FieldDecl {{.*}} used fi 'INT':'int' +//CHECK-NEXT: | |-CXXMethodDecl {{.*}} F 'void ()' +//CHECK-NEXT: | | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-CXXConstructorDecl {{.*}} +//CHECK-NEXT: | | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-CXXConstructorDecl {{.*}} +//CHECK-NEXT: | | `-ParmVarDecl {{.*}} 'const S &' +//CHECK-NEXT: | `-CXXConstructorDecl {{.*}} +//CHECK-NEXT: | `-ParmVarDecl {{.*}} 'S &&' + +void Bar(S *ps) { + ps->fi = 0; +} + +//CHECK: |-FunctionDecl {{.*}} used Bar 'void (S *)' +//CHECK-NEXT: | |-ParmVarDecl {{.*}} used ps 'S *' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: | `-BinaryOperator {{.*}} +//CHECK-NEXT: | |-MemberExpr {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'ps' 'S *' +//CHECK-NEXT: | `-IntegerLiteral {{.*}} + +void Foo() { + S s; + Bar(&s); + S::si = 2; +} + +//CHECK: `-FunctionDecl {{.*}} used Foo 'void ()' +//CHECK-NEXT: `-CompoundStmt {{.*}} +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} used s 'S' callinit +//CHECK-NEXT: | `-CXXConstructExpr {{.*}} +//CHECK-NEXT: |-CallExpr {{.*}} +//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'Bar' 'void (S *)' +//CHECK-NEXT: | `-UnaryOperator {{.*}} +//CHECK-NEXT: | `-DeclRefExpr {{.*}} 's' 'S' +//CHECK-NEXT: `-BinaryOperator {{.*}} +//CHECK-NEXT: |-DeclRefExpr {{.*}} 'si' 'int' +//CHECK-NEXT: `-IntegerLiteral {{.*}} Index: test/SemaCXX/used_template.cpp =================================================================== --- test/SemaCXX/used_template.cpp +++ test/SemaCXX/used_template.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace + +template +T B(T param) { + typedef T TYPE; + typedef int I; + TYPE var; + var = 1; + return ++param; +} + +//CHECK: | `-FunctionDecl {{.*}} used B 'int (int)' +//CHECK-NEXT: | |-TemplateArgument type 'int' +//CHECK-NEXT: | |-ParmVarDecl {{.*}} used param 'int':'int' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-TypedefDecl {{.*}} used TYPE 'int':'int' +//CHECK-NEXT: | | `-SubstTemplateTypeParmType {{.*}} +//CHECK-NEXT: | | |-TemplateTypeParmType {{.*}} +//CHECK-NEXT: | | | `-TemplateTypeParm {{.*}} +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-TypedefDecl {{.*}} I 'int' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-VarDecl {{.*}} used var 'TYPE':'int' +//CHECK-NEXT: | |-BinaryOperator {{.*}} 'TYPE':'int' lvalue '=' +//CHECK-NEXT: | | |-DeclRefExpr {{.*}} +//CHECK-NEXT: | | `-IntegerLiteral {{.*}} +//CHECK-NEXT: | `-ReturnStmt {{.*}} +//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | `-UnaryOperator {{.*}} +//CHECK-NEXT: | `-DeclRefExpr {{.*}} + +void Bar() { + B(1); +} + +//CHECK: `-FunctionDecl {{.*}} Bar 'void ()' +//CHECK-NEXT: `-CompoundStmt {{.*}} +//CHECK-NEXT: `-CallExpr {{.*}} +//CHECK-NEXT: |-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | `-DeclRefExpr {{.*}} +//CHECK-NEXT: `-IntegerLiteral {{.*}} Index: test/SemaCXX/used_typedef.cpp =================================================================== --- test/SemaCXX/used_typedef.cpp +++ test/SemaCXX/used_typedef.cpp @@ -0,0 +1,100 @@ +// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace + +namespace A { + typedef int INTEGER; + typedef char CHAR; + namespace B { + typedef int INTEGER; + typedef char CHAR; + struct S { + typedef int INTEGER; + typedef char CHAR; + }; + } +} + +//CHECK: |-NamespaceDecl {{.*}} used A +//CHECK-NEXT: | |-TypedefDecl {{.*}} used INTEGER 'int' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | |-TypedefDecl {{.*}} CHAR 'char' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | `-NamespaceDecl {{.*}} used B +//CHECK-NEXT: | |-TypedefDecl {{.*}} used INTEGER 'int' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | |-TypedefDecl {{.*}} CHAR 'char' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | `-CXXRecordDecl {{.*}} used struct S definition +//CHECK-NEXT: | |-DefinitionData {{.*}} +//CHECK-NEXT: | | |-DefaultConstructor {{.*}} +//CHECK-NEXT: | | |-CopyConstructor {{.*}} +//CHECK-NEXT: | | |-MoveConstructor {{.*}} +//CHECK-NEXT: | | |-CopyAssignment {{.*}} +//CHECK-NEXT: | | |-MoveAssignment {{.*}} +//CHECK-NEXT: | | `-Destructor {{.*}} +//CHECK-NEXT: | |-CXXRecordDecl {{.*}} implicit struct S +//CHECK-NEXT: | |-TypedefDecl {{.*}} used INTEGER 'int' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | `-TypedefDecl {{.*}} CHAR 'char' +//CHECK-NEXT: | `-BuiltinType {{.*}} + +typedef int INTEGER; +typedef char CHAR; + +//CHECK: |-TypedefDecl {{.*}} used INTEGER 'int' +//CHECK-NEXT: | `-BuiltinType {{.*}} +//CHECK-NEXT: |-TypedefDecl {{.*}} CHAR 'char' +//CHECK-NEXT: | `-BuiltinType {{.*}} + +void Foo() { + typedef char CHAR; + + typedef int INTEGER; + INTEGER L_I; + L_I = 1; + + ::INTEGER G_I; + G_I = 1; + + A::B::S::INTEGER M_N_S_I; + M_N_S_I = 1; + + A::B::INTEGER M_N_I; + M_N_I = 1; + + A::INTEGER M_I; + M_I = 1; +} + +//CHECK: `-FunctionDecl {{.*}} used Foo 'void ()' +//CHECK-NEXT: `-CompoundStmt {{.*}} +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-TypedefDecl {{.*}} CHAR 'char' +//CHECK-NEXT: | `-BuiltinType {{.*}} 'char' +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-TypedefDecl {{.*}} used INTEGER 'int' +//CHECK-NEXT: | `-BuiltinType {{.*}} 'int' +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} used L_I 'INTEGER':'int' +//CHECK-NEXT: |-BinaryOperator {{.*}} 'INTEGER':'int' lvalue '=' +//CHECK-NEXT: | |-DeclRefExpr {{.*}} 'INTEGER':'int' lvalue Var {{.*}} 'L_I' 'INTEGER':'int' +//CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 1 +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} used G_I '::INTEGER':'int' +//CHECK-NEXT: |-BinaryOperator {{.*}} '::INTEGER':'int' lvalue '=' +//CHECK-NEXT: | |-DeclRefExpr {{.*}} '::INTEGER':'int' lvalue Var {{.*}} 'G_I' '::INTEGER':'int' +//CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 1 +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} used M_N_S_I 'A::B::S::INTEGER':'int' +//CHECK-NEXT: |-BinaryOperator {{.*}} 'A::B::S::INTEGER':'int' lvalue '=' +//CHECK-NEXT: | |-DeclRefExpr {{.*}} 'A::B::S::INTEGER':'int' lvalue Var {{.*}} 'M_N_S_I' 'A::B::S::INTEGER':'int' +//CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 1 +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} used M_N_I 'A::B::INTEGER':'int' +//CHECK-NEXT: |-BinaryOperator {{.*}} 'A::B::INTEGER':'int' lvalue '=' +//CHECK-NEXT: | |-DeclRefExpr {{.*}} 'A::B::INTEGER':'int' lvalue Var {{.*}} 'M_N_I' 'A::B::INTEGER':'int' +//CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 1 +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} used M_I 'A::INTEGER':'int' +//CHECK-NEXT: `-BinaryOperator {{.*}} 'A::INTEGER':'int' lvalue '=' +//CHECK-NEXT: |-DeclRefExpr {{.*}} 'A::INTEGER':'int' lvalue Var {{.*}} 'M_I' 'A::INTEGER':'int' +//CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1 Index: test/SemaCXX/used_using.cpp =================================================================== --- test/SemaCXX/used_using.cpp +++ test/SemaCXX/used_using.cpp @@ -0,0 +1,162 @@ +// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace + +namespace A { + typedef char CHAR; +} + +//CHECK: |-NamespaceDecl {{.*}} used A +//CHECK-NEXT: | `-TypedefDecl {{.*}} used CHAR 'char' +//CHECK-NEXT: | `-BuiltinType {{.*}} + +namespace B { + typedef char CHAR; +} + +//CHECK: |-NamespaceDecl {{.*}} used B +//CHECK-NEXT: | `-TypedefDecl {{.*}} used CHAR 'char' +//CHECK-NEXT: | `-BuiltinType {{.*}} + +namespace C { + typedef char CHAR; + typedef int INTEGER; + typedef unsigned UNSIGNED; + + void FA(); + void FB(); + + int Var1; + int Var2; +} + +//CHECK: |-NamespaceDecl {{.*}} used C +//CHECK-NEXT: | |-TypedefDecl {{.*}} CHAR 'char' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | |-TypedefDecl {{.*}} INTEGER 'int' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | |-TypedefDecl {{.*}} UNSIGNED 'unsigned int' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | |-FunctionDecl {{.*}} used FA 'void ()' +//CHECK-NEXT: | |-FunctionDecl {{.*}} used FB 'void ()' +//CHECK-NEXT: | |-VarDecl {{.*}} used Var1 'int' +//CHECK-NEXT: | `-VarDecl {{.*}} used Var2 'int' + +using A::CHAR; +using B::CHAR; + +//CHECK: |-UsingDecl {{.*}} A::CHAR +//CHECK-NEXT: |-UsingShadowDecl {{.*}} 'CHAR' +//CHECK-NEXT: | `-TypedefType {{.*}} 'A::CHAR' sugar +//CHECK-NEXT: | |-Typedef {{.*}} +//CHECK-NEXT: | `-BuiltinType {{.*}} +//CHECK-NEXT: |-UsingDecl {{.*}} B::CHAR +//CHECK-NEXT: |-UsingShadowDecl {{.*}} 'CHAR' +//CHECK-NEXT: | `-TypedefType {{.*}} 'B::CHAR' sugar +//CHECK-NEXT: | |-Typedef {{.*}} 'CHAR' +//CHECK-NEXT: | `-BuiltinType {{.*}} + +void F1() { + using A::CHAR; + CHAR ca; + ca = '1'; + + using B::CHAR; + B::CHAR cb; + cb = '1'; +} + +//CHECK: |-FunctionDecl {{.*}} used F1 'void ()' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-UsingDecl {{.*}} used A::CHAR +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-VarDecl {{.*}} used ca 'A::CHAR':'char' +//CHECK-NEXT: | |-BinaryOperator {{.*}} +//CHECK-NEXT: | | |-DeclRefExpr {{.*}} 'ca' 'A::CHAR':'char' +//CHECK-NEXT: | | `-CharacterLiteral {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-UsingDecl {{.*}} B::CHAR +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-VarDecl {{.*}} used cb 'B::CHAR':'char' +//CHECK-NEXT: | `-BinaryOperator {{.*}} +//CHECK-NEXT: | |-DeclRefExpr {{.*}} 'cb' 'B::CHAR':'char' +//CHECK-NEXT: | `-CharacterLiteral {{.*}} + +void F2() { + using C::FA; + FA(); + + using C::Var1; + Var1 = 2; + + using C::FB; + C::FB(); + + using C::Var2; + C::Var2 = 2; +} + +//CHECK: |-FunctionDecl {{.*}} used F2 'void ()' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-UsingDecl {{.*}} used C::FA +//CHECK-NEXT: | |-CallExpr {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-UsingDecl {{.*}} used C::Var1 +//CHECK-NEXT: | |-BinaryOperator {{.*}} +//CHECK-NEXT: | | |-DeclRefExpr {{.*}} +//CHECK-NEXT: | | `-IntegerLiteral {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-UsingDecl {{.*}} C::FB +//CHECK-NEXT: | |-CallExpr {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'FB' 'void ()' +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-UsingDecl {{.*}} C::Var2 +//CHECK-NEXT: | `-BinaryOperator {{.*}} +//CHECK-NEXT: | |-DeclRefExpr {{.*}} 'Var2' 'int' +//CHECK-NEXT: | `-IntegerLiteral {{.*}} + +void F3() { + using namespace C; + C::FA(); + + namespace CC = C; + using namespace CC; + CC::FA(); +} + +//CHECK: |-FunctionDecl {{.*}} used F3 'void ()' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-UsingDirectiveDecl {{.*}} Namespace {{.*}} 'C' +//CHECK-NEXT: | |-CallExpr {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'FA' 'void ()' +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-NamespaceAliasDecl {{.*}} used CC +//CHECK-NEXT: | | `-Namespace {{.*}} 'C' +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-UsingDirectiveDecl {{.*}} Namespace {{.*}} 'C' +//CHECK-NEXT: | `-CallExpr {{.*}} +//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | `-DeclRefExpr {{.*}} 'FA' 'void ()' + +void Bar() { + F1(); + F2(); + F3(); +} + +//CHECK: `-FunctionDecl {{.*}} Bar 'void ()' +//CHECK-NEXT: `-CompoundStmt {{.*}} +//CHECK-NEXT: |-CallExpr {{.*}} +//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | `-DeclRefExpr {{.*}} 'F1' 'void ()' +//CHECK-NEXT: |-CallExpr {{.*}} +//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | `-DeclRefExpr {{.*}} 'F2' 'void ()' +//CHECK-NEXT: `-CallExpr {{.*}} +//CHECK-NEXT: `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: `-DeclRefExpr {{.*}} 'F3' 'void ()'